I am trying to configure a Fortran 2008 project to use CMake; the files in the project have the ".f08" extension. However, I cannot get CMake to work even with a "hello world" example. Here are the relevant parts of my CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8)
project (hello)
enable_language (Fortran)
set (CMAKE_Fortran_SOURCE_FILE_EXTENSIONS ${CMAKE_Fortran_SOURCE_FILE_EXTENSIONS} "f08;F08")
add_executable ("hello-world" "hello-world.f08")
set_target_properties (hello-world PROPERTIES LINKER_LANGUAGE Fortran)
Three notes:
The Makefile generated does not compile "hello-world.f08" into an object file.
The "set_target_properties" is needed. Otherwise, CMake reports that it "can not determine linker language for target:hello-world".
Renaming the file to "hello-world.f95" along with the corresponding change in CMakeLists.txt makes things work. Even the "set_target_properties" command is no longer needed.
If you need to specify Fortran files with unrecognized extensions, you can set the source file's LANGUAGE property, e.g.:
set_source_files_properties(hello-world.f08 PROPERTIES LANGUAGE Fortran)
Related
I am using cmake 3.8.1 with the FindSWIG und UseSWIG "extensions" for using swig as code generator. The "swig .i" file contains an include statement to a file in a different directory. The important part of my CMakeLists.txt looks like this:
...
find_package (TCL REQUIRED)
if (TCL_FOUND)
set (HAVE_TCL_H 1)
endif (TCL_FOUND)
find_package (SWIG )
if (SWIG_FOUND)
include(${SWIG_USE_FILE})
set (SWIG_FILE /home/steve/cmake_games/src/foo/bar/bar_swig.i)
set_property(SOURCE ${SWIG_FILE} PROPERTY CPLUSPLUS ON)
swig_add_library (bar_tclext LANGUAGE tcl SOURCES ${SWIG_FILE})
include_directories (/home/steve/cmake_games/src/foo/bar /home/steve/cmake_games/src/this/that)
set_target_properties(bar_tclext PROPERTIES LINKER_LANGUAGE CXX)
swig_link_libraries(bar_tclext ${TCL_LIBRARY})
endif (SWIG_FOUND)
cmake generates make files without a problem. Executing make however leads to the following error message
/home/steve/cmake_games/src/foo/bar/bar_swig.i:3: Error: Unable to find 'that.iih'
that.iih is located in /home/steve/cmake_games/src/this/that
Looking at the swig call in the generated Makefile I can see that swig is not called with an include path.
You might think that CMakeLists.txt with absolute paths is weird. True! This is the case due to the fact that the CMakeLists.txt are generated by scripts that take advantage of our conventions in directory topology and naming. We want keep enforcing this by generating the CMakeLists.txt as part of the "configure" process.
What do I need to change in the CMakeLists.txt?
you should try to setup CMAKE_SWIG_FLAGS in your case something like:
list(APPEND CMAKE_SWIG_FLAGS
"-I/home/steve/cmake_games/src/foo/bar"
"-I/home/steve/cmake_games/src/this/that")
e.g.: https://github.com/google/or-tools/blob/master/cmake/python.cmake#L57
ps: if you have compile definitions you should also pass them to SWIG by hand since you can't say to swig macro to get all the properties of an associated target.
This is similar to Force CMake to use C++ compiler for C files with Visual Studio, but its not quite the same. Its not the same because a its CMake file causing the failure; and I'm working on nearly every modern platform, from BSDs and OS X through Solaris and Unix.
I tried to avoid useless checks being performed by CMake:
project(cryptopp, CXX)
Here's what happens when I attempt to generate the makefile:
$ cmake .
-- Check if the system is big endian
-- Searching 16 bit integer
-- Check size of unsigned short
CMake Error at /usr/share/cmake-2.8/Modules/CheckTypeSize.cmake:82 (try_compile):
Unknown extension ".c" for file
/home/jeffrey/cryptopp/CMakeFiles/CheckTypeSize/CMAKE_SIZEOF_UNSIGNED_SHORT.c
try_compile() works only for enabled languages. Currently these are:
CXX
See project() command to enable other languages.
Call Stack (most recent call first):
/usr/share/cmake-2.8/Modules/CheckTypeSize.cmake:167 (__check_type_size_impl)
/usr/share/cmake-2.8/Modules/TestBigEndian.cmake:27 (CHECK_TYPE_SIZE)
CMakeLists.txt:49 (TEST_BIG_ENDIAN)
We don't have any C files in our project, so we should be safe with project(cryptopp, CXX) (if I am reading cmake --help-command project correctly).
The cited question talks about project files, but not CMake files.
How do I tell CMake to use C++ compiler for all files, including its own CMake files?
I'm on Ubuntu 12 LTS, and it provides:
$ cmake --version
cmake version 2.8.7
There are ways to add .c as a valid file extension for the CXX compiler. Even this being very advanced CMake stuff, you may need - if you are bound to support older versions of CMake - a "make rules overwrite script" anyway.
So I've successfully tested the following:
CryptoppMakeRulesOverwrite.cmake
list(APPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS c)
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.7 FATAL_ERROR)
set(CMAKE_USER_MAKE_RULES_OVERRIDE "CryptoppMakeRulesOverwrite.cmake")
project(cryptopp CXX)
include(CheckTypeSize)
CHECK_TYPE_SIZE("unsigned short" CMAKE_SIZEOF_UNSIGNED_SHORT)
As #Tsyvarev has commented check_type_size() supports a LANGUAGE parameter, but unfortunately not for CMake version 2.8.7. But this older version does already support CMAKE_USER_MAKE_RULES_OVERRIDE.
So I'm still wondering if not the best solution would be to go to a newer version of CMake (forcing some users of older CMake versions to upgrade). Or writing your own try_compile() snippets.
References
How to add in a CMake project a global file extension (*.pde) to GCC which is treated like C++ code
Change default value of CMAKE_CXX_FLAGS_DEBUG and friends in CMake
set_source_files_properties
The CMake setting of (my) choice here would be the set_source_files_properties command. https://cmake.org/cmake/help/latest/command/set_source_files_properties.html
set(qpid_dispatch_SOURCES
alloc.c
alloc_pool.c
aprintf.c
amqp.c
atomic.c
# [...]
)
set_source_files_properties(${qpid_dispatch_SOURCES} PROPERTIES LANGUAGE CXX)
add_library(qpid-dispatch OBJECT ${qpid_dispatch_SOURCES})
As described in the linked docs, CMake 3.18 changed the scoped effect of set_source_files_properties. See the DIRECTORY and TARGET_DIRECTORY options. Therefore, to apply source file property recursively to all files in your project, your CMakeLists.txt should look something like this
cmake_minimum_required(VERSION 3.20)
project(qpid-dispatch LANGUAGES C CXX)
# [...]
add_subdirectory(src)
add_subdirectory(tests)
add_subdirectory(router)
# [...]
file(GLOB_RECURSE CFILES "*.c")
set_source_files_properties(${CFILES}
DIRECTORY src tests router
PROPERTIES LANGUAGE CXX)
Copy the world
There is another approach that I've heard can be made to work: in your CMakeLists.txt, recursively copy all *.c files into *.cpp files and declare separate CMake targets to compile the copies. This has the advantage of allowing you to produce C-compiled and CXX-compiled artifacts at the same time, should you need anything like that.
Another braindead way of doing this (I just tried the set_source_files_properties() route and it just didn't even try to compile the files).
Rather than figure out the rats nest of cmake stuff I'm saddled with, I just added a C++ file that #includes the .c file, and added the C++ file to the CMakeLists.txt sources.
Braindead and stupid, but I'm having to deal with horrific code I'm importing. C header files without extern "C" in them, being used by C++ files.
This is similar to Force CMake to use C++ compiler for C files with Visual Studio, but its not quite the same. Its not the same because a its CMake file causing the failure; and I'm working on nearly every modern platform, from BSDs and OS X through Solaris and Unix.
I tried to avoid useless checks being performed by CMake:
project(cryptopp, CXX)
Here's what happens when I attempt to generate the makefile:
$ cmake .
-- Check if the system is big endian
-- Searching 16 bit integer
-- Check size of unsigned short
CMake Error at /usr/share/cmake-2.8/Modules/CheckTypeSize.cmake:82 (try_compile):
Unknown extension ".c" for file
/home/jeffrey/cryptopp/CMakeFiles/CheckTypeSize/CMAKE_SIZEOF_UNSIGNED_SHORT.c
try_compile() works only for enabled languages. Currently these are:
CXX
See project() command to enable other languages.
Call Stack (most recent call first):
/usr/share/cmake-2.8/Modules/CheckTypeSize.cmake:167 (__check_type_size_impl)
/usr/share/cmake-2.8/Modules/TestBigEndian.cmake:27 (CHECK_TYPE_SIZE)
CMakeLists.txt:49 (TEST_BIG_ENDIAN)
We don't have any C files in our project, so we should be safe with project(cryptopp, CXX) (if I am reading cmake --help-command project correctly).
The cited question talks about project files, but not CMake files.
How do I tell CMake to use C++ compiler for all files, including its own CMake files?
I'm on Ubuntu 12 LTS, and it provides:
$ cmake --version
cmake version 2.8.7
There are ways to add .c as a valid file extension for the CXX compiler. Even this being very advanced CMake stuff, you may need - if you are bound to support older versions of CMake - a "make rules overwrite script" anyway.
So I've successfully tested the following:
CryptoppMakeRulesOverwrite.cmake
list(APPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS c)
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.7 FATAL_ERROR)
set(CMAKE_USER_MAKE_RULES_OVERRIDE "CryptoppMakeRulesOverwrite.cmake")
project(cryptopp CXX)
include(CheckTypeSize)
CHECK_TYPE_SIZE("unsigned short" CMAKE_SIZEOF_UNSIGNED_SHORT)
As #Tsyvarev has commented check_type_size() supports a LANGUAGE parameter, but unfortunately not for CMake version 2.8.7. But this older version does already support CMAKE_USER_MAKE_RULES_OVERRIDE.
So I'm still wondering if not the best solution would be to go to a newer version of CMake (forcing some users of older CMake versions to upgrade). Or writing your own try_compile() snippets.
References
How to add in a CMake project a global file extension (*.pde) to GCC which is treated like C++ code
Change default value of CMAKE_CXX_FLAGS_DEBUG and friends in CMake
set_source_files_properties
The CMake setting of (my) choice here would be the set_source_files_properties command. https://cmake.org/cmake/help/latest/command/set_source_files_properties.html
set(qpid_dispatch_SOURCES
alloc.c
alloc_pool.c
aprintf.c
amqp.c
atomic.c
# [...]
)
set_source_files_properties(${qpid_dispatch_SOURCES} PROPERTIES LANGUAGE CXX)
add_library(qpid-dispatch OBJECT ${qpid_dispatch_SOURCES})
As described in the linked docs, CMake 3.18 changed the scoped effect of set_source_files_properties. See the DIRECTORY and TARGET_DIRECTORY options. Therefore, to apply source file property recursively to all files in your project, your CMakeLists.txt should look something like this
cmake_minimum_required(VERSION 3.20)
project(qpid-dispatch LANGUAGES C CXX)
# [...]
add_subdirectory(src)
add_subdirectory(tests)
add_subdirectory(router)
# [...]
file(GLOB_RECURSE CFILES "*.c")
set_source_files_properties(${CFILES}
DIRECTORY src tests router
PROPERTIES LANGUAGE CXX)
Copy the world
There is another approach that I've heard can be made to work: in your CMakeLists.txt, recursively copy all *.c files into *.cpp files and declare separate CMake targets to compile the copies. This has the advantage of allowing you to produce C-compiled and CXX-compiled artifacts at the same time, should you need anything like that.
Another braindead way of doing this (I just tried the set_source_files_properties() route and it just didn't even try to compile the files).
Rather than figure out the rats nest of cmake stuff I'm saddled with, I just added a C++ file that #includes the .c file, and added the C++ file to the CMakeLists.txt sources.
Braindead and stupid, but I'm having to deal with horrific code I'm importing. C header files without extern "C" in them, being used by C++ files.
I want the CMake Gui to Change the .lib and .dll names with defined postfixes like:
_vs12_d64(_omp_off)
If this is not possible via the CMake Gui how to do this in the CMake file.
Postfixes can be added using CMAKE_DEBUG_POSTFIX and CMAKE_RELEASE_POSTFIX depending on CMAKE_BUILD_TYPE.
You can either set these values globally or use set_target_properties to change it only for specific targets.
You need to do this in the corresponding CMakeLists.txt file, see the following example:
project(test)
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_DEBUG_POSTFIX "_debug_postfix")
set(CMAKE_RELEASE_POSTFIX "_release_postfix")
add_library(test test.c)
This will generate libtest_debug_postfix.a.
I am using CMake 2.8.7 on a Linux machine with Intel 11.0 compilers. I am trying to use CMake for the first time as I would like to build this project on both Windows and Linux machines.
I though of using a simple approach first and used a standard Hello World example:
My src/HelloWorld.f90:
!Test helloworld in Fortran using Cmake
program hello
print *, "Hello World!"
end program hello
My main CMakeLists.txt:
# States that CMake required version must be greater than 2.8.7
cmake_minimum_required(VERSION 2.8.7)
enable_language (Fortran)
project(helloworld Fortran)
add_subdirectory(src)
SET_TARGET_PROPERTIES(helloworld PROPERTIES LINKER_LANGUAGE FORTRAN)
My src/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.7)
# Include the directory itself as a path to include directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# For a large number of source files you can create it in a simpler way
# using file() function:
file(GLOB helloworld_SOURCES *.f90)
I still get an error which says CMAKE_FORTRAN_LINK_EXECUTABLE variable missing. I looked at Abinader's CMake tutorial#1, but haven't had success so far.
any suggestions?? Thanks in advance !
Not a direct answer, as I've never used fortran with cmake, but I can see a few issues here.
First of all: where is your target helloworld defined? project is not a target.
Secondly: where do you use helloworld_SOURCES variable?
Try a more regular way. In your src/CMakeLists.txt add line at the end of file with:
add_executable(helloworld ${helloworld_SOURCES})
Also remove SET_TARGET_PROPERTIES(helloworld PROPERTIES LINKER_LANGUAGE FORTRAN) from main one as it should not be necessary.
Last advice: try not to use file(GLOB ). It is better to define list of all files manualy.
Probably the upper-case "FORTRAN", when setting the linker language is the problem. Try writing it as "Fortran" as in the enable_language statement. CMake derives the variables it uses from the language and this causes CMake to look for CMAKE_FORTRAN_LINK_EXECUTABLE instead of CMAKE_Fortran_LINK_EXECUTABLE.
As also mentioned by Michal, the add_executable has to be added to your CMakeLists.txt.
I tested your issue with the following CMake configurations files
main CMakeLists.txt:
# States that CMake required version must be greater than 2.8.7
cmake_minimum_required(VERSION 2.8.7)
enable_language (Fortran)
project(helloworld Fortran)
add_subdirectory(src)
src/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.7)
add_executable(helloworld HelloWorld.f90)
under Linux for following versions:
ifort (IFORT) 16.0.0.20150815
cmake version 2.8.12.2
I prefer to use cmake-gui. There you can define the ifort compiler as follows:
After definition of source code and binary folder, e.g. build, press "Configure" and select
Click "Next" and define the following compilers
Click "Finish" and "Generate".
Go to build/src folder and execute make. The helloworld executable is generated with ifort successfully and could be called here.
Hint: If ifort is already the default native compiler on your Linux computer then you don't have to specify it in cmake-gui and can go ahead with the first option "Use default native compilers".
Hope it helps.
Let's try this step-by-step:
1) Your Fortran Hello, world is OK!
src/hello.f90
!Test helloworld in Fortran using Cmake
program hello
print *, "Hello World!"
end program hello
2) Now let's write the "inner" CMakeLists.txt
src/CMakeLists.txt
add_executable(helloworld hello.f90)
set_target_properties(
helloworld
PROPERTIES
LINKER_LANGUAGE Fortran
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build)
Here we've created an executable file, which you haven't in your question. Also, we've set its linker language to Fortran (it's case-sensitive parameter!) and the output directory for the compiled file.
3) Now we'll create the "main" CMakeLists.txt
CMakeLists.txt
# States that CMake required version must be greater than 2.8.7
cmake_minimum_required(VERSION 2.8.7)
project(helloworld Fortran)
add_subdirectory(src)
Here we've specified the src subdirectory with inner CMakeLists.txt and the compiler language - it's enough to use project() function, there's not need to use it together with enable_language().
4) Finally, let's build our code in out-of-source manner and run it!
cmake -S . -B build
cmake --build build
./build/helloworld