I'm creating makefiles to build Fortran projects on Linux. Our current work flow is to develop on Windows in VS with Intel Fortran (build in VS), then port the project source code to Linux and build there using a makefile and the Intel Linux Fortran. The next project to port has several hundred Fortran source files. Are automated tools available to create the Linux makefile from the Windows VS .vfproj project file?
The best leads I've found from web searching are these:
This Intel article recommends using the information from the BuildLog.htm file to help create a makefile: https://software.intel.com/en-us/articles/can-i-export-a-makefile-from-visual-studio
Would it be best to rebuild the solution so that all the source files get listed in the BuildLog.htm file? Then use a text editor to create the rules to compile each source file? Is the order of the files in the BuildLog.htm significant in terms of .mod dependencies? I'm guessing I'll need to be careful to get the module dependencies handled correctly in the make file.
This forum topic listed a few tools that could help: https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/270229
Has anyone used one of these tools, such as Makedepf90, to create a makefile? (http://personal.inet.fi/private/erikedelmann/makedepf90/) If yes, was it useful, and advice on using it?
Some Stackoverflow articles recommended creating the makefile manually [to "build" character I suppose ;-) ].
Thanks for your help.
The Intel compiler supports /gen-dep (-gen-dep) which outputs make-compatible dependency info per compilation. This will go a long way towards your makefile.
The compiler option name helps a bunch! I found that it is available in VS in the Project -> Properties -> Fortran -> Output Files form, where the "Build Dependencies (/gen-dep)" can be set to "Yes", and the "Emit Build Dependencies to File" can be set to "Yes". Changing those two options and building the solution (looks like adding those options triggered a rebuild solution) did create the <project>.dep text file. The file format is even makefile friendly with the output as: target : dependencies
That *.dep file should help me fill in the bulk of the makefile with the many rules for the source file compile targets.
Thank you for the help.
Could you provide some more details how to convert .dep file into makefile?
I am new to make, and currently looking for a quick and smooth solution to make my VS project cross-platform. I have a lot of module + submodule relations and the compilation of this outside VS is not that trivial.
From your comment ("The file format is even makefile friendly with the output as: target : dependencies") it seems that conversion may be straightforward.
Once I obtained the *.dep file from Visual Studio and Intel Fortran (on Windows) I did some text parsing of the file listing in the .dep file to get the format I wanted for the makefile. To get a .dep file with all the source files and their dependencies I did a rebuild all from VS so that all the project files would be included in the .dep file. A small example with one module "file1_module.f90" and one subroutine "AreaSub.f90" would give the .dep file:
file1_module.mod : \ C:\project\file1_module.f90 x64\Release\AreaSub.obj : \ C:\project\AreaSub.f90 x64\Release\file1_module.mod
The module depends on its source file, and the subroutine depends on its source file and the .mod file, which is located in the x64\Release subfolder of the project on Windows. Depending on the project and number of source files manual text parsing may be adequate in a text editor. For larger projects with many more source files I wrote a parsing routine (in Fortran) that reads through the .dep file and gets the file names to put them into the makefile friendly format.
I have been creating a makefile for both Windows and Linux. That way I can run the Windows makefile using "nmake" and get a dll to run on Windows for comparison to the binary from building using VS, which has worked very well. Then I can move the source files to Linux and make the *.so shared object library file there. Much of the makefile is the same for Linux, so I just need to change the compile options, file extension, etc. Using the .dep file gives the file names and dependencies to create the build rules at the bottom of the makefile. An example makefile for Windows (seems that nmake on Windows ignores the bash script shebang top line, so I left it in):
#!/bin/bash # # makefile to build the dynamic link library *.dll file on Windows, # open the initialized Intel Parallel Studio console (CMD) window so that # the Fortran environment variables are set. # # use "nmake" command on Windows: nmake -f make_file_name # # define some variables, # some of the options obtained from the Visual Studio project properties, # use "\" as a continuation line # objects = file1_module.obj \ AreaSub.obj compiler = ifort options = /nologo /libs:dll /threads # # compiler options for Windows (similar to Linux), # O2 for optimization for speed, # fpconstant to evaluate single-precision constants as double precision # warn:declarations to check for undeclared names, # warn:unused to check for declared variables that are never used # opt1 = /O2 /warn:declarations /warn:unused /fpconstant # # compile and link the source files to build the dll "area.dll", # use the /dll option to get a DLL instead of an EXE, # use the /exe:filename option to give the name of the DLL file # area.dll: $(objects) $(compiler) /dll /exe:fortlog.dll $(objects) $(opt1) $(options) file1_module.obj: file1_module.f90 $(compiler) /c file1_module.obj $(opt1) AreaSub.obj: AreaSub.f90 $(compiler) /c AreaSub.f90 file1_module.obj $(opt1)
Then I change a few items for the Linux makefile. Change the compile options, change the object file extension to ".o", and change the compile option to "-c":
#!/bin/bash # # makefile to build the shared object library *.so file on Linux, # expecting the Intel Fortran compiler environment variables to be initialized # # use command: make -f make_file_name # # define some variables, # use "\" as a continuation line # on Linux use the ".o" object file extension (".obj" on Windows) # objects = file1_module.o \ AreaSub.o compiler = ifort options = -shared -fPIC -static-intel # # compiler options for Linux (similar to Windows), # the -fPIC for "position independent code", option is needed for each subroutine # when building the shared object, # O2 for optimization for speed, # fpconstant to evaluate single-precision constants as double precision, # warn:declarations to check for undeclared names, # warn:unused to check for declared variables that are never used # opt1 = -fPIC -O2 -fpconstant -warn declarations -warn unused # # compile and link the source files to get the shared object library libarea.so, # begin the shared object library file name with "lib" so that Linux can find the file, # the libarea.so library depends on the $(objects) listed above, # on Linux use the "-c" compile option ("/c" on Windows), # using the file1_module.o object file seems to be sufficient for AreaSub.o get updated, # could also try a dependency on the .mod file # area.so: $(objects) $(compiler) -o libarea.so $(objects) $(options) file1_module.o: file1_module.f90 $(compiler) -c file1_module.o $(opt1) AreaSub.o: AreaSub.f90 $(compiler) -c AreaSub.f90 file1_module.o $(opt1)
It is certainly possible to add more source files for a larger project. The makefile could use subdirectories to organize the object files and take advantage of declaring more variables to define directories and other options, but I've left that out for this example. Does the example .dep output from VS and the example makefiles help? How many source files do you have, and would more automated parsing of the .dep file be needed?
Thanks Greg for posting this. It is nice to have this for reference. Something like this belongs in a How To... in the IVF documentation and other places like Stackoverflow.
Hi Jim, Thanks for the encouragement. Is there a way for me to post an example to a How To or FAQ, or is that up to someone else? I could post to Stackoverflow too, perhaps adding the source files to give a more complete example.
I'd like to correct a typo I noticed in the Windows makefile for the name of the DLL. I had been testing the /exe naming option and didn't change back to the original "area.dll". The area.dll syntax should be (replace fortlog.dll with area.dll):
area.dll: $(objects) $(compiler) /dll /exe:area.dll $(objects) $(opt1) $(options)
Great thanks for your support. I succeeded in moving the compilation of a simple VS project (main+modules+submodules) into makefile. The lessons learnt are:
1) I am using Visual Studio 2013 Shell and I do not nmake there - I had to install regular VS on my machine,
2) What I only need from .dep file is the list of .F90 files (in the proper order!). This is an input to objects= list (with modified file extension). This lists sets the order of .F90 files compilation and linking (again, I am not make expert).
3) I think you do not need to have file1_module.o in:
The file1_module.f90 is compiled to .mod file in the current directory and AreaSub.f90 sees it.
Concluding.. 1) From BuildLog I will take compiler flags. 2) I am preparing a script which goes through .dep file and pulls out only strings defining .F90 and .F files. 3) I will input this list to objects= variable. 4) I will create a loop that goes through all .F90 and .F files and prints out sth like this:
file_name(i_arg).o: file_name(i_arg).f90 $(compiler) -c file_name(i_arg).f90 $(opt1)
I will apply this concept to my real project (I have about 300 .F90 + .F files in various locations, module-submodule dependencies, including external libraries, etc..). If I have further thoughts I will definitely comment here.
I'm glad to hear you're making progress with your make file. If you have 300 source files in a project it will be worthwhile to automate the text parsing of the .dep file list to help create the syntax to compile using make. I think it is a useful exercise to write a routine in Fortran to help do the parsing, gather the file names, and write them in the format that make uses. Adding the compile options manually seems to not be too much effort.
For the make file example above, I wanted to show the module dependency in the subroutine's compile instructions. In this example my intent is for the subroutine "AreaSub.o" to be dependent on both its source file "AreaSub.f90" and on the module file "file1_module.o". My understanding of make is that it will check to see if file1_module.o is newer than AreaSub.o, and if so it will also recompile AreaSub.f90 to get the updated AreaSub.o before linking the project files. That way if the file1_module.f90 source file is updated, but AreaSub.f90 is not updated, the make file will automatically recompile file1_module.f90 and also any files that depend on file1_module.o. That can help avoid needing to do a rebuild all for the entire project, especially is there are many source files. I believe that if AreaSub.o does not have a dependency on the file1_module.o and doesn't get recompiled when needed there could be compile and link errors, and possibly run time errors.
Hopefully adding the dependencies as needed will help give you a useful make file.