Fortran file dependency with Intel ifort - module

I am working in a standard Unix environment, with Intel Fortran 2012 compiler.
since my codes have some old .f files and some newer .f90 files, the makefile is organized in the following structure,
f_sources= ... ...
f90_sources= ... ...
f_objects = $(patsubst %.f,%.o,$(f_sources))
f90_objects = $(patsubst %.f90,%.o,$(f90_sources))
$(f_objects): %.o: %.f
#echo compiling $<
$(FC) $(FC_FLAGS) -c $< -o $#
# compile f90 files:
$(f90_objects): %.o: %.f90
#echo compiling $<
$(FC) $(FC_FLAGS) -c $< -o $#
The problem is, few strange .f files depend on the modules defined in some .f90 files, and then the compiler seems not able to detect the dependency since I compile first all the .f files...
Error in opening the compiled module file. Check INCLUDE paths.
Is there a way to solve this problem?

Add
f77_file_with_module_dependency.o: f90_file_for_module.o
to your Makefile somewhere.

Supposing that you have a there.f file that depends on mod_here.f90, you declare in your makefile the following:
there.o: mod_here.o
$(FC) $(FC_FLAG) -c there.f -o there.o
When the makefile gets to this file, there.f, it will see that it depends on mod_here.f90, which hasn't yet been compiled, so it'll compile it.

Related

How can I tell CMake to put include directory flags after the compiler option flags in its object compile command?

I am facing problems due to the target holding the include paths first and then the compiler options after. How can I set the include paths after the compiler options for compiling source files of a target?
My CMakeLists.txt file:
project(HelloWorld)
cmake_minimum_required(VERSION 3.0)
add_library(HELLO_WORLD_LIB
STATIC
src/helloWorld.cpp
)
target_include_directories(
HELLO_WORLD_LIB AFTER PUBLIC D:\\temp\\includes
)
target_compile_options(HELLO_WORLD_LIB BEFORE PUBLIC -cpp -remap)
set_target_properties(HELLO_WORLD_LIB
PROPERTIES
OUTPUT_NAME hello
ARCHIVE_OUTPUT_DIRECTORY D:\\temp\\CMakeHelloWorld
SUFFIX .a
)
My cmake call:
call cmake -GNinja -S ./.. -DCMAKE_INSTALL_PREFIX=../_bin
call cmake --build . --config Debug --verbose -d keeprsp
call cmake --install .
The console output:
-- Configuring done
-- Generating done
-- Build files have been written to: D:/temp/CMakeHelloWorld/_build
[1/2] C:\mingw\test25_comp_8.1.0_testversion\bin\c++.exe -ID:/temp/includes -cpp -remap -MD -MT CMakeFiles/HELLO_WORLD_LIB.dir/src/helloWorld.cpp.obj -MF CMakeFiles\HELLO_WORLD_LIB.dir\src\helloWorld.cpp.obj.d -o CMakeFiles/HELLO_WORLD_LIB.dir/src/helloWorld.cpp.obj -c ../src/helloWorld.cpp
[2/2] cmd.exe /C "cd . && C:\toolbase\_ldata\cmake\.8-3.20.2\bin\cmake.exe -E rm -f ..\libhello.a && C:\mingw\test25_comp_8.1.0_testversion\bin\ar.exe qc ..\libhello.a CMakeFiles/HELLO_WORLD_LIB.dir/src/helloWorld.cpp.obj && C:\toolbase\mingw\test25_comp_8.1.0_testversion\bin\ranlib.exe ..\libhello.a && cd ."
-- Install configuration: ""
However if I try to add the include paths after compiler options, it sits before the compiler options. How can I set the compiler options before the include directories? like C:\toolbase\mingw\test25_comp_8.1.0_testversion\bin\c++.exe -cpp -remap -ID:/temp/includes.
The relevant CMake variable is CMAKE_CXX_COMPILE_OBJECT, which is the configuration point for what template to use for the command to compile an object. The default value is set in Modules/CMakeCXXInformation.cmake, and overrides are specified in various Modules/Platform/* or Modules/Compiler/* files. If you're curious, you can grep for the overrides with the following regex: set.*CXX_COMPILE_OBJECT.
The default one is set like this:
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
You probably want something like this (set it in your own CMakeLists.txt file, or in a toolchain file):
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> <DEFINES> <FLAGS> <INCLUDES> -o <OBJECT> -c <SOURCE>")
As far as I can tell, this configuration point is "global". I'm not aware of how to specify it with different values for different targets or source files.
If you're working with the Ninja generator and need this kind of change to affect the generated .rsp files, I think you'd need to build a modified version of CMake from source, since that behaviour seems to be baked into the binaries instead of CMake script files in the Modules/ directory. The relecant source file is Source/cmNinjaTargetGenerator.cxx. Look at the lines of code that do rule.RspContent = and you'll see:
rule.RspContent =
cmStrCat(' ', scanVars.Defines, ' ', scanVars.Includes, ' ', scanFlags);
You'd probably need to switch the order of scanVars.Includes and scanVars.scanFlags.
If you choose to make a modified CMake binary, as always, make sure you comply with the software licence.

CMake ninja custom target used as pre-build command modifies the files but ninja see the change of the depndecies during next build

I run some command before the actual build
add_custom_target("${PROJECT_BUILD_NUM_FILE}"
COMMAND ${PROJECT_BUILD_NUM_UPDATE} "-p" "-x" -f ${PROJECT_SOURCE_DIR}/${MAIN_PATH}/${BOARD_NAME}/${PROJECT_BUILD_NUM_FILE}
)
add_dependencies(${EXECUTABLE_NAME} "${PROJECT_BUILD_NUM_FILE}" )
When I build first time (the project was build before)
>------ Build started: Project: CMakeLists, Configuration: Debug ------
[1/1] cmd.exe /C "cd /D C:\Users\Piotr\git\gPIMS-EG\out\build\IoT-Debug && C:\Users\Piotr\git\gPIMS-EG\stm-libs\pc-exe\buildnum.exe -p -x -f C:/Users/Piotr/git/gPIMS-EG/src/EG/BuildID.h"
Build number file used:C:/Users/Piotr/git/gPIMS-EG/src/EG/BuildID.h
Build file updated: Build Number: 22 DateCode: 0x1d6d
Build succeeded.
BuildID.h file was modified and saved. Modification date is set correctly.
On the second build it behaves correctly
>------ Build started: Project: CMakeLists, Configuration: Debug ------
[1/4] cmd.exe /C "cd /D C:\Users\Piotr\git\gPIMS-EG\out\build\IoT-Debug && C:\Users\Piotr\git\gPIMS-EG\stm-libs\pc-exe\buildnum.exe -p -x -f C:/Users/Piotr/git/gPIMS-EG/src/EG/BuildID.h"
Build number file used:C:/Users/Piotr/git/gPIMS-EG/src/EG/BuildID.h
Build file updated: Build Number: 23 DateCode: 0x1d6d
[2/4] C:\PROGRA~2\Atollic\TRUEST~1.0\ARMTools\bin\AR097D~1.EXE -DALLOW_SOFTWARE_BKPTS=1 -DARM_MATH_CM4 -DBOOTLOADER_VERSION=1 -DCOMPILE_FOR_EG=1 -DDEBUGFILEWRITE=1 -DDEBUG_RUN_WITHOUT_CHECKS=1 -DFORCE_CUBE_USB -DHSE_VALUE=8000000UL -DSLOWSPIDEBUG=0 -DSTM32L -DSTM32L476xx -DSTM32L4xx -DUSE_EMBEDDED_PHY=1 -DUSE_FULL_ASSERT -DUSE_FULL_LL_DRIVER="" -DUSE_HAL_DRIVER -DUSE_SWOTRACE=1 -DUSE_USB_OTG_FS=1 -DUSE_USB_OTG_HS=1 -D_DEBUG=1 -D_GNU_SOURCE=1 -D__USE_SIMPLE_SWO=0 -I../../../src -I../../../src/EG -I../../../src/ZM -I../../../src/inc -I../../../stm-libs/inc -I../../../stm-libs/Drivers -I../../../stm-libs/Services -I../../../stm-libs/Services/Utils -I../../../stm-libs/RTOS/Source/include -I../../../stm-libs/RTOS/Source/portable/GCC/ARM_CM4F -I../../../stm-libs/Libraries/CMSIS/Include -I../../../stm-libs/Libraries/CMSIS/Device/ST/STM32L4xx/Include -I../../../stm-libs/Libraries/CryptoLib/Inc -I../../../stm-libs/Libraries/CryptoLib/Inc/RNG -I../../../stm-libs/drivers/USBD -I../../../stm-libs/Libraries/Middlewares/ST/STM32_USB_Device_Library/Core/Inc -I../../../stm-libs/Libraries/USB/Device/Class/CDC/Inc -I../../../stm-libs/Libraries/USB/Device/Class/MSC_HID/Inc -I../../../stm-libs/Libraries/USB/Device/Core/Inc -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7 -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7/arch -I../../../stm-libs/Libraries/lwip/src -I../../../stm-libs/Libraries/lwip/src/include -I../../../stm-libs/drivers/USBH -I../../../stm-libs/Libraries/USB/Host/Class/AUDIO/Inc -I../../../stm-libs/Libraries/USB/Host/Class/CDC/Inc -I../../../stm-libs/Libraries/USB/Host/Class/HID/Inc -I../../../stm-libs/Libraries/USB/Host/Class/MSC/Inc -I../../../stm-libs/Libraries/USB/Host/Class/MTP/Inc -I../../../stm-libs/Libraries/USB/Host/Core/Inc -I../../../stm-libs/Libraries/USB/Host/Class/Template/Inc -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7/FreeRTOS -I../../../stm-libs/Libraries/misc -I../../../stm-libs/Libraries/FatFs/src -I../../../stm-libs/Libraries/littleFS -I../../../stm-libs/Apps -I../../../stm-libsApps/SeqZM -I../../../stm-libs/Libraries/libc_e -I../../../stm-libs/Libraries -I../../../stm-hal-l4/Inc/Legacy -I../../../stm-hal-l4/Inc -I../../../stm-libs/Apps/Other -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Og -g3 -T"C:/Users/Piotr/git/gPIMS-EG/src/EG/startup/EG.ld" -L"C:/Users/Piotr/git/gPIMS-EG/stm-libs/Libraries/CryptoLib" -lSTM32CryptographicV3.0.0_CM4_GCC_FPU -specs=nosys.specs -specs=nano.specs -Wl,-Map="EG.map" -static -Wl,-u,Reset_Handler -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -ffunction-sections -fdata-sections -g -MD -MT CMakeFiles/GCEG-FW.dir/stm-libs/Apps/common/SC_Ver.c.obj -MF CMakeFiles\GCEG-FW.dir\stm-libs\Apps\common\SC_Ver.c.obj.d -o CMakeFiles/GCEG-FW.dir/stm-libs/Apps/common/SC_Ver.c.obj -c ../../../stm-libs/Apps/common/SC_Ver.c
In file included from ../../../stm-libs/Apps/common/SC_Ver.c:9:0:
C:\Users\Piotr\git\gPIMS-EG\stm-libs\Drivers\CAN-COB.h(267,2): warning GF07C7A44: #warning added to compile BP to change [-Wcpp]
#warning added to compile BP to change
^~~~~~~
[3/4] C:\PROGRA~2\Atollic\TRUEST~1.0\ARMTools\bin\AR097D~1.EXE -DALLOW_SOFTWARE_BKPTS=1 -DARM_MATH_CM4 -DBOOTLOADER_VERSION=1 -DCOMPILE_FOR_EG=1 -DDEBUGFILEWRITE=1 -DDEBUG_RUN_WITHOUT_CHECKS=1 -DFORCE_CUBE_USB -DHSE_VALUE=8000000UL -DSLOWSPIDEBUG=0 -DSTM32L -DSTM32L476xx -DSTM32L4xx -DUSE_EMBEDDED_PHY=1 -DUSE_FULL_ASSERT -DUSE_FULL_LL_DRIVER="" -DUSE_HAL_DRIVER -DUSE_SWOTRACE=1 -DUSE_USB_OTG_FS=1 -DUSE_USB_OTG_HS=1 -D_DEBUG=1 -D_GNU_SOURCE=1 -D__USE_SIMPLE_SWO=0 -I../../../src -I../../../src/EG -I../../../src/ZM -I../../../src/inc -I../../../stm-libs/inc -I../../../stm-libs/Drivers -I../../../stm-libs/Services -I../../../stm-libs/Services/Utils -I../../../stm-libs/RTOS/Source/include -I../../../stm-libs/RTOS/Source/portable/GCC/ARM_CM4F -I../../../stm-libs/Libraries/CMSIS/Include -I../../../stm-libs/Libraries/CMSIS/Device/ST/STM32L4xx/Include -I../../../stm-libs/Libraries/CryptoLib/Inc -I../../../stm-libs/Libraries/CryptoLib/Inc/RNG -I../../../stm-libs/drivers/USBD -I../../../stm-libs/Libraries/Middlewares/ST/STM32_USB_Device_Library/Core/Inc -I../../../stm-libs/Libraries/USB/Device/Class/CDC/Inc -I../../../stm-libs/Libraries/USB/Device/Class/MSC_HID/Inc -I../../../stm-libs/Libraries/USB/Device/Core/Inc -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7 -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7/arch -I../../../stm-libs/Libraries/lwip/src -I../../../stm-libs/Libraries/lwip/src/include -I../../../stm-libs/drivers/USBH -I../../../stm-libs/Libraries/USB/Host/Class/AUDIO/Inc -I../../../stm-libs/Libraries/USB/Host/Class/CDC/Inc -I../../../stm-libs/Libraries/USB/Host/Class/HID/Inc -I../../../stm-libs/Libraries/USB/Host/Class/MSC/Inc -I../../../stm-libs/Libraries/USB/Host/Class/MTP/Inc -I../../../stm-libs/Libraries/USB/Host/Core/Inc -I../../../stm-libs/Libraries/USB/Host/Class/Template/Inc -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7/FreeRTOS -I../../../stm-libs/Libraries/misc -I../../../stm-libs/Libraries/FatFs/src -I../../../stm-libs/Libraries/littleFS -I../../../stm-libs/Apps -I../../../stm-libsApps/SeqZM -I../../../stm-libs/Libraries/libc_e -I../../../stm-libs/Libraries -I../../../stm-hal-l4/Inc/Legacy -I../../../stm-hal-l4/Inc -I../../../stm-libs/Apps/Other -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Og -g3 -T"C:/Users/Piotr/git/gPIMS-EG/src/EG/startup/EG.ld" -L"C:/Users/Piotr/git/gPIMS-EG/stm-libs/Libraries/CryptoLib" -lSTM32CryptographicV3.0.0_CM4_GCC_FPU -specs=nosys.specs -specs=nano.specs -Wl,-Map="EG.map" -static -Wl,-u,Reset_Handler -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -ffunction-sections -fdata-sections -g -MD -MT CMakeFiles/GCEG-FW.dir/stm-libs/Apps/WaveMC3/waveMC3SeqGUI.c.obj -MF CMakeFiles\GCEG-FW.dir\stm-libs\Apps\WaveMC3\waveMC3SeqGUI.c.obj.d -o CMakeFiles/GCEG-FW.dir/stm-libs/Apps/WaveMC3/waveMC3SeqGUI.c.obj -c ../../../stm-libs/Apps/WaveMC3/waveMC3SeqGUI.c
In file included from ../../../stm-libs/Drivers/CAN-G3M.h:31:0,
from ../../../stm-libs/Drivers/ioCmd.h:12,
from ../../../stm-libs/Services/srvCmd.h:9,
from ../../../src/EG/../ZM/zmServices.h:10,
from ../../../src/EG/ourServices.h:12,
from ../../../stm-libs/Apps/WaveMC3/waveMC3SeqGUI.c:5:
C:\Users\Piotr\git\gPIMS-EG\stm-libs\Drivers\CAN-COB.h(267,2): warning GF07C7A44: #warning added to compile BP to change [-Wcpp]
#warning added to compile BP to change
^~~~~~~
[4/4] cmd.exe /C "cd . && C:\PROGRA~2\Atollic\TRUEST~1.0\ARMTools\bin\AR097D~1.EXE -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Og -g3 -T"C:/Users/Piotr/git/gPIMS-EG/src/EG/startup/EG.ld" -L"C:/Users/Piotr/git/gPIMS-EG/stm-libs/Libraries/CryptoLib" -lSTM32CryptographicV3.0.0_CM4_GCC_FPU -specs=nosys.specs -specs=nano.specs -Wl,-Map="EG.map" -static -Wl,-u,Reset_Handler -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -ffunction-sections -fdata-sections -g #CMakeFiles\GCEG-FW.rsp -o GCEG-FW.elf && cmd.exe /C "cd /D C:\Users\Piotr\git\gPIMS-EG\out\build\IoT-Debug && "C:\Program Files (x86)\Atollic\TrueSTUDIO for STM32 9.3.0\ARMTools\bin\arm-atollic-eabi-objcopy.exe" GCEG-FW.elf --output-target=binary GCEG-FW.bin -j .isr_vector -j .VERSION_INFO -j .text -j .rodata -j .ARM.extab -j .ARM -j .preinit_array -j .init_array -j .fini_array -j .data -j .RAM_VectorTable -j .RAM_DATAfunctions -j .RAM_functions -v && "C:\Program Files (x86)\Atollic\TrueSTUDIO for STM32 9.3.0\ARMTools\bin\arm-atollic-eabi-size.exe" GCEG-FW.elf --format=Berkeley""
copy from `GCEG-FW.elf' [elf32-littlearm] to `GCEG-FW.bin' [binary]
text data bss dec hex filename
210428 36680 54020 301128 49848 GCEG-FW.elf
Build succeeded.
It looks like ninja is checking dependencies before the actual build starts and ignores meanwhile file changed. Is there any way to force cmake/ninja to recheck dependecies after custom target is build (ie prgram that thenges the build is run).
It looks like ninja is checking dependencies before the actual build starts and ignores meanwhile file change
Hey! Yes. Because DEPFILEs from C source files are generated at the same time as they are compiled, cmake has no way to know beforehand which file depends on which. It would have to do two passes - first to get dependencies and then to compile (which would be a nice feature, but actually hard to implement). It happens in one pass during compilation (-MD -MT flags), so cmake has no way of knowing that one file depends on that header. I also advise:
Do not modify files in your source tree. Keep all changes in BINARY_DIR.
Do not modify files. Generate new files. It's easier and generally, less state = less problems.
Try it such:
# Inside binary_dir
set(PROJECT_BUILD_NUM_FILE ${CMAKE_CURRENT_BINARY_DIR}/gen/buildid_gen.h)
# Add #include <buildid_gen.h> to your buildid.h
add_custom_command(
OUTPUT ${PROJECT_BUILD_NUM_FILE}
COMMAND ${PROJECT_BUILD_NUM_UPDATE} "-p" "-x" -f ${PROJECT_BUILD_NUM_FILE}
DEPENDS ${PROJECT_BUILD_NUM_UPDATE}
)
add_custom_target(buildid_gen
COMMENT "Yooohooo!"
DEPENDS ${PROJECT_BUILD_NUM_FILE}
)
add_executable(${EXECUTABLE_NAME} ${PROJECT_BUILD_NUM_FILE} ${some_other_sources})
target_add_include_directories(${EXECTABLE_NAME} PUBLIC
# add include directory, so that buildid_gen is found
${CMAKE_CURRENT_BINARY_DIR}/gen
)
# this *helps*
add_dependencies(${EXECUTABLE_NAME} buildid_gen)
Is there any way to force cmake/ninja to recheck dependecies after custom target is build (ie prgram that thenges the build is run).
The real proper way ™ would be to manually track all files that depend on the file (you could think of grep -l '#include <buildid_gen.h> to get the list files) and communicate to cmake the dependency relation:
add_source_file_properties(${sources_that_include_buildid_gen} PROPERTIES OBJECT_DEPENDS ${PROJECT_BUILD_NUM_FILE})
Tracking dependencies is easier if you use a runtime interface (ie. long get_build_id();) cause then only one .c file that implements the interface will depend on the generated file.
There are also some projects that are compiled in two passes because of such dependencies, you have to first cmake .. --target buildid_gen and then cmake .. --target actually_compile each time you compile.
Also maybe execute_process is more appropriate if the file is setup once per build.

Can I use CMake to compile a program in stages?

I'm using the LLVM compiler to perform some analyses. I also have a test application I've written that I build using CMake. I'd like to compile the test application in stages:
Compile all source files of the test application to LLVM bitcode.
Link all of the bitcode files together using llvm-link.
Compile this linked bitcode file down into an actual binary (using an extra flag to run my analyses).
As an example, if I had a program test comprised of 3 files, foo.c, bar.c, and bar.h:
Normal compilation:
clang -I. -c foo.c // generates foo.o
clang -I. -c bar.c // generates bar.o
ld -lc -lgcc -o test foo.o bar.o // links foo.o and bar.o
Bitcode compilation & linking:
clang -I. -c -emit-llvm foo.c // generates foo.bc
clang -I. -c -emit-llvm bar.c // generates bar.bc
llvm-link -o test.bc foo.bc bar.bc // links foo.bc and bar.bc
clang -I. -o test test.bc // generates test
As I said, I've already written CMake files that build and compile the test application normally (i.e., in a single stage).
Is it possible, through some combination of adding custom commands and/or targets, to achieve such a thing? Or should I continue with my current approach of using bash/Python scripts to run this process?

How do I build/compile Fortran with MinGW gfortran via CMake?

I've got much more I've got to get figured out with CMake than just the following problem, but it's the first and simplest one which I still can't get past. I've scoured the interwebs and even borrowed the 'Mastering CMake' book from a friend, but I'm still having the hardest time... A lot of stuff exists online with regards to CMake, Fortran, and MinGW, and even combinations of two at a time. But all three together seem to be almost non-existent.
All I want to do (at this point) is get a simple Fortran program built and compiling using CMake on Windows, using MinGW's gfortran compiler.
...And I'm a CMake n00b.
This is what I've been working with so far:
CMakeLists.txt:
project(cmake_test Fortran)
add_executable(testf test.f90)
test.f90:
program test
write(*,*)"hello world"
endprogram test
I've got the MSYS2 version of MinGW, since that's the only version that the code I'm eventually going to be compiling will compile with on Windows. (Ie. when I compile it with my own Makefile in the MSYS2 shell, it compiles.)
I've got my Windows Path appended with ;C:\msys64\mingw64\bin. (I've also tried ;C:\msys64\usr\bin, but it complains about sh.exe being in the same directory, among other issues.)
Then I pop open the CMake-GUI, load in the CMakeLists above, hit Configure, specify the generator for the project to be "MinGW Makefiles", select "Use default native compilers", and get the following output:
The Fortran compiler identification is GNU 5.4.0
Check for working Fortran compiler: C:/msys64/mingw64/bin/gfortran.exe
Check for working Fortran compiler: C:/msys64/mingw64/bin/gfortran.exe -- works
Detecting Fortran compiler ABI info
Detecting Fortran compiler ABI info - done
Checking whether C:/msys64/mingw64/bin/gfortran.exe supports Fortran 90
Checking whether C:/msys64/mingw64/bin/gfortran.exe supports Fortran 90 -- yes
Configuring done
Then I click Configure again and get:
Configuring done
Then Generate:
Generating done
In my build directory there is then a Makefile and a number of other files and directories.
I try running make in the MSYS2 shell, and I get this:
myself#COMPUTER MSYS /c/users/myself/desktop/dll_test/with_fortran_cmake/build
$ make
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\users\myself\desktop\dll_test\with_fortran_cmake\build>
That last line is a prompt. If I type stuff like make it seems to run it again and it just brings up the prompt again, within the prompt. If I hit Ctrl+C, it kills it and returns to the normal MSYS2 prompt.
So I can't figure out how to actually make it, assuming I'm even doing the CMake part right.
Question: How do I get this example code to build/compile/run given the constraints I've listed?
(What I'd actually rather do, once I get past this part, is get it to work with Visual Studio 13, since I have a C++ project being built with CMake (written mostly by someone else to whom I have limited access for questions and aid) from which I want to be able to call my Fortran. Once I get the Fortran into a library of some sort which is callable by the C++ from Visual Studio, the Fortran can pretty much just be left alone as a pre-built library. I know that editing Fortran from VS is not really much of a possibility, and I'm not interested in doing it.)
Here are the contents of the generated Makefile (note my editor replaced tabs with spaces when I copied it here):
# CMAKE generated file: DO NOT EDIT!
# Generated by "MinGW Makefiles" Generator, CMake Version 3.5
# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
.NOTPARALLEL:
#=============================================================================
# Special targets provided by cmake.
# Disable implicit rules so canonical targets will work.
.SUFFIXES:
# Remove some rules from gmake that .SUFFIXES does not remove.
SUFFIXES =
.SUFFIXES: .hpux_make_needs_suffix_list
# Suppress display of executed commands.
$(VERBOSE).SILENT:
# A target that is always out of date.
cmake_force:
.PHONY : cmake_force
#=============================================================================
# Set environment variables for the build.
SHELL = cmd.exe
# The CMake executable.
CMAKE_COMMAND = "C:\Program Files (x86)\CMake\bin\cmake.exe"
# The command to remove a file.
RM = "C:\Program Files (x86)\CMake\bin\cmake.exe" -E remove -f
# Escaping for special characters.
EQUALS = =
# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = C:\Users\myself\Desktop\dll_test\with_fortran_cmake
# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = C:\Users\myself\Desktop\dll_test\with_fortran_cmake\build
#=============================================================================
# Targets provided globally by CMake.
# Special rule for the target edit_cache
edit_cache:
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..."
"C:\Program Files (x86)\CMake\bin\cmake-gui.exe" -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : edit_cache
# Special rule for the target edit_cache
edit_cache/fast: edit_cache
.PHONY : edit_cache/fast
# Special rule for the target rebuild_cache
rebuild_cache:
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
"C:\Program Files (x86)\CMake\bin\cmake.exe" -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache
# Special rule for the target rebuild_cache
rebuild_cache/fast: rebuild_cache
.PHONY : rebuild_cache/fast
# The main all target
all: cmake_check_build_system
$(CMAKE_COMMAND) -E cmake_progress_start C:\Users\myself\Desktop\dll_test\with_fortran_cmake\build\CMakeFiles C:\Users\myself\Desktop\dll_test\with_fortran_cmake\build\CMakeFiles\progress.marks
$(MAKE) -f CMakeFiles\Makefile2 all
$(CMAKE_COMMAND) -E cmake_progress_start C:\Users\myself\Desktop\dll_test\with_fortran_cmake\build\CMakeFiles 0
.PHONY : all
# The main clean target
clean:
$(MAKE) -f CMakeFiles\Makefile2 clean
.PHONY : clean
# The main clean target
clean/fast: clean
.PHONY : clean/fast
# Prepare targets for installation.
preinstall: all
$(MAKE) -f CMakeFiles\Makefile2 preinstall
.PHONY : preinstall
# Prepare targets for installation.
preinstall/fast:
$(MAKE) -f CMakeFiles\Makefile2 preinstall
.PHONY : preinstall/fast
# clear depends
depend:
$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles\Makefile.cmake 1
.PHONY : depend
#=============================================================================
# Target rules for targets named testf
# Build rule for target.
testf: cmake_check_build_system
$(MAKE) -f CMakeFiles\Makefile2 testf
.PHONY : testf
# fast build rule for target.
testf/fast:
$(MAKE) -f CMakeFiles\testf.dir\build.make CMakeFiles/testf.dir/build
.PHONY : testf/fast
test.obj: test.f90.obj
.PHONY : test.obj
# target to build an object file
test.f90.obj:
$(MAKE) -f CMakeFiles\testf.dir\build.make CMakeFiles/testf.dir/test.f90.obj
.PHONY : test.f90.obj
test.i: test.f90.i
.PHONY : test.i
# target to preprocess a source file
test.f90.i:
$(MAKE) -f CMakeFiles\testf.dir\build.make CMakeFiles/testf.dir/test.f90.i
.PHONY : test.f90.i
test.s: test.f90.s
.PHONY : test.s
# target to generate assembly for a file
test.f90.s:
$(MAKE) -f CMakeFiles\testf.dir\build.make CMakeFiles/testf.dir/test.f90.s
.PHONY : test.f90.s
# Help Target
help:
#echo The following are some of the valid targets for this Makefile:
#echo ... all (the default if no target is provided)
#echo ... clean
#echo ... depend
#echo ... testf
#echo ... edit_cache
#echo ... rebuild_cache
#echo ... test.obj
#echo ... test.i
#echo ... test.s
.PHONY : help
#=============================================================================
# Special targets to cleanup operation of make.
# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles\Makefile.cmake 0
.PHONY : cmake_check_build_system
Version information:
GNU Fortran (GCC) 5.3.0
Windows 7 Enterprise
Cmake 3.5.2
MSYS2 - I'm not sure how to find the version for this
MinGW - I'm not sure how to find the version for this
I've been through a lot of different pages online during my search, and I didn't bother keeping track of them all, but this one in particular is one I keep coming across because it seems like it's very related from the title, but the actual issue and resolution are totally not:
How can I get a basic Fortran file to compile on Windows/MinGW using CMake?
Here is a quick shell session showing how I was able to build your Fortran program using MSYS2, cmake, make, and gfortran. You should try running the same commands that I did and see if they give different outputs then investigate the reason.
The MSYSTEM variable is especially important; it is determined by what shortcut you click on when starting MSYS2.
$ echo $MSYSTEM
MINGW64
$ which cmake
/mingw64/bin/cmake
$ which gfortran
/mingw64/bin/gfortran
$ which make
/usr/bin/make
$ ls
CMakeLists.txt test.f90
$ cat CMakeLists.txt
project(cmake_test Fortran)
add_executable(testf test.f90)
$ cat test.f90
program test
write(*,*)"hello world"
endprogram test
$ mkdir build && cd build
$ cmake -G"MSYS Makefiles" ..
-- The Fortran compiler identification is GNU 6.2.0
-- Check for working Fortran compiler: D:/msys64/mingw64/bin/gfortran.exe
-- Check for working Fortran compiler: D:/msys64/mingw64/bin/gfortran.exe -- works
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Checking whether D:/msys64/mingw64/bin/gfortran.exe supports Fortran 90
-- Checking whether D:/msys64/mingw64/bin/gfortran.exe supports Fortran 90 -- yes
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/david/Documents/scraps/test_fortran/build
$ make
Scanning dependencies of target testf
[ 50%] Building Fortran object CMakeFiles/testf.dir/test.f90.obj
[100%] Linking Fortran executable testf.exe
[100%] Built target testf
$ ./testf.exe
hello world
Edit: There IS a working solution here -- read till the end!
Thanks to David Grayson's comment on the original question, I've found a partial solution. "Partial" because it uses f95 instead of gfortran. I'm posting it because it might work for someone else, and if I'm able to figure out how to get it to work with gfortran, I'll just update it.
Turns out the main issue was a pretty simple mistake: I was using "MinGW Makefiles" instad of "MSYS Makefiles".
When I only changed that, however, I got the following output in the CMake-GUI when I clicked Configure:
CMake Error: CMake was unable to find a build program corresponding to "MSYS Makefiles". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool.
CMake Error: CMake was unable to find a build program corresponding to "MSYS Makefiles". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool.
CMake Error: CMAKE_Fortran_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_AR was not found, please set to archive program. Configuring incomplete, errors occurred!
To fix this, I changed my Windows Path again. I'd been using ;C:\msys64\mingw64\bin, and so I switched it to ;C:\msys64\usr\bin.
This then worked (I clicked Configure a second time, clicked Generate, and then ran make via the MSYS2 terminal in the /build directory), but as you can see in the following output, it used f95 instead of gfortran:
The Fortran compiler identification is GNU 5.3.0
Check for working Fortran compiler: C:/msys64/usr/bin/f95.exe
Check for working Fortran compiler: C:/msys64/usr/bin/f95.exe -- works
Detecting Fortran compiler ABI info
Detecting Fortran compiler ABI info - done
Checking whether C:/msys64/usr/bin/f95.exe supports Fortran 90
Checking whether C:/msys64/usr/bin/f95.exe supports Fortran 90 -- yes
Configuring done
I'm still working to get it to use gfortran, and I'll update this solution if I figure it out.
Edit:
Okay, this is obviously more of a hack and I'm sure that there's a better solution. I renamed C:\msys64\usr\bin\f95.exe to something else (so that MSYS2 wouldn't find it as another Fortran compiler before finding gfortran). I also had to clear CMake's cache and restart it. But now it works:
The Fortran compiler identification is GNU 5.3.0
Check for working Fortran compiler: C:/msys64/usr/bin/gfortran.exe
Check for working Fortran compiler: C:/msys64/usr/bin/gfortran.exe -- works
Detecting Fortran compiler ABI info
Detecting Fortran compiler ABI info - done
Checking whether C:/msys64/usr/bin/gfortran.exe supports Fortran 90
Checking whether C:/msys64/usr/bin/gfortran.exe supports Fortran 90 -- yes
Configuring done
Working on figuring out how to do this the "correct" way.
Edit:
Okay, I'm guessing this is the more proper way to do it, as I assume it essentially does the same thing as setting environment variables on the commandline when calling CMake from there.
In the CMake-GUI, I set everything up as explained before, but before clicking Configure for the first time, I clicked the "Add Entry" button with the little plus symbol. I then set two new Cache Entries -- though only one is really necessary:
Name: CMAKE_Fortran_COMPILER
Type: FILEPATH
Value: C:\msys64\usr\bin\gfortran.exe
I also set the following, but this was only to verify that it was calling gfortran properly, as you'll see in the output below:
Name: CMAKE_VERBOSE_MAKEFILE
Type: BOOL
Value: [True]
Then, running make in the MSYS2 terminal, I got the following:
$ make
"/C/Program Files (x86)/CMake/bin/cmake.exe" -H/C/Users/myself/Desktop/dll_test/with_fortran_cmake -B/C/Users/myself/Desktop/dll_test/with_fortran_cmake/build --check-build-system CMakeFiles/Makefile.cmake 0
"/C/Program Files (x86)/CMake/bin/cmake.exe" -E cmake_progress_start /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build/CMakeFiles /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
make -f CMakeFiles/testf.dir/build.make CMakeFiles/testf.dir/depend
make[2]: Entering directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
"/C/Program Files (x86)/CMake/bin/cmake.exe" -E cmake_depends "MSYS Makefiles" /C/Users/myself/Desktop/dll_test/with_fortran_cmake /C/Users/myself/Desktop/dll_test/with_fortran_cmake /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build/CMakeFiles/testf.dir/DependInfo.cmake --color=
Scanning dependencies of target testf
make[2]: Leaving directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
make -f CMakeFiles/testf.dir/build.make CMakeFiles/testf.dir/requires
make[2]: Entering directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
make[2]: Nothing to be done for 'CMakeFiles/testf.dir/requires'.
make[2]: Leaving directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
make -f CMakeFiles/testf.dir/build.make CMakeFiles/testf.dir/build
make[2]: Entering directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
[ 50%] Building Fortran object CMakeFiles/testf.dir/test.f90.obj
/C/msys64/usr/bin/gfortran.exe -c /C/Users/myself/Desktop/dll_test/with_fortran_cmake/test.f90 -o CMakeFiles/testf.dir/test.f90.obj
[100%] Linking Fortran executable testf.exe
"/C/Program Files (x86)/CMake/bin/cmake.exe" -E remove -f CMakeFiles/testf.dir/objects.a
/C/msys64/usr/bin/ar.exe cr CMakeFiles/testf.dir/objects.a #CMakeFiles/testf.dir/objects1.rsp
/C/msys64/usr/bin/gfortran.exe -Wl,--whole-archive CMakeFiles/testf.dir/objects.a -Wl,--no-whole-archive -o testf.exe -Wl,--out-implib,libtestf.dll.a -Wl,--major-image-version,0,--minor-image-version,0
make[2]: Leaving directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
[100%] Built target testf
make[1]: Leaving directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
"/C/Program Files (x86)/CMake/bin/cmake.exe" -E cmake_progress_start /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build/CMakeFiles 0
And the resulting program works both via the MSYS2 terminal and a Windows command prompt.
...Now I need to figure out how to get this all together with C++ in Visual Studio. Stay tuned for more SO questions! :D

Cross-platform static-linking SDL2

I'm building an SDL2/C++ program that needs to be portable to Windows, Mac, and Linux machines which may not have SDL installed.
I've read that static linking is the solution, but I'm not very good with compiling and don't know how to static link.
My program relies only on SDL2, GLU, and OpenGL. I'm compiling C++ with either MinGW (on Windows 8.1) or gcc (on Ubuntu 14.04) -- both of these OS's have SDL installed natively.
Here is my current makefile, derived from a sample makefile given to me by a professor of mine:
# Executable/file name
EXE=experiment
# MinGW
ifeq "$(OS)" "Windows_NT"
CFLG=-O3 -Wall -DUSEGLEW
LIBS= -lSDL2 -lglu32 -lopengl32
CLEAN=del *.exe *.o *.a
else
# OSX
ifeq "$(shell uname)" "Darwin"
CFLG=-O3 -Wall -Wno-deprecated-declarations
LIBS=-framework SDL2 -framework OpenGL
# Linux\Unix\Solaris
else
CFLG=-O3 -Wall
LIBS= `sdl2-config --cflags --libs` -lGLU -lGL -lm
endif
# OSX\Linux\Unix\Solaris
CLEAN=rm -f $(EXE) *.o *.a
endif
# Dependencies
$(EXE).o: $(EXE).cpp FORCE
.c.o:
gcc -c -o $# $(CFLG) $<
.cpp.o:
g++ -std=c++11 -c -o $# $(CFLG) $<
# Link
$(EXE):$(EXE).o
g++ -std=c++11 -O3 -o $# $^ $(LIBS)
# Clean
clean:
$(CLEAN)
# Force
FORCE:
To link with static library you either specify path to library file
gcc -o out_bin your_object_files.o path/to/lib.a -lfoo
or ask linker to use static version with -Bstatic linker flag. Usually you'll want to reset linking back to dynamic for the rest of the libraries, e.g. for static SDL2 and GLU but dynamic GL:
gcc -o out_bin your_object_files -Wl,-Bstatic -lSDL2 -lGLU -Wl,-Bdynamic -lGL
That of course implies that static versions of libraries are present in library search path list (.a libs for gcc on all specified platforms, although MSVC uses .lib for static libraries).
However you usually don't really want to do that at all. It is common practice for software to either depend on some libs (widespread on linux, with packages and dependendices lists) or bring required libraries with it. You can just distribute SDL dynamic library with your program and load it with LD_LIBRARY_PATH or relative rpath.
Please also note that newer SDL2 implements dynamic loading of functions which provides a way to override SDL with user-specified dynamic library, even if linked statically.
It wasn't related directly to static linking. When static linking, I had to include all of SDL's dependency libraries. Turns out, having -mwindows causes console communication to fail.