I have a Fortran project that I've compiled into mex. It has a bunch of Fortran files that have to be linked together, and some mex libraries. Using a Makefile like the one below, I was able to get this to work:
MEX=/opt/matlab/r2018a/bin/mex
FORTRAN = gfortran
FFLAGS = -c -fpic -fopenmp -Wall -O3 -fdefault-real-8 -fdefault-double-8
MEXLIBDIR = /opt/matlab/r2018a/sys/os/glnxa64
MEXLIB = -lgfortran -liomp5 -lirc -lsvml -limf
OBJS=\
file_a.o\
file_b.o\
all: file_a file_b mex
mex: mex_executable.F $(OBJS)
$(MEX) -v -O mex_exectuable.F $(OBJS) -L$(MEXLIBDIR) $(MEXLIB)
file_a: file_a.f
$(FORTRAN) $(FFLAGS) file_a.f
file_b: file_b.f
$(FORTRAN) $(FFLAGS) file_b.f
Since I'll have several projects like this, I'd like to put everything into a single CMake file.
So far, I have a CMakeLists.txt that looks something like this, inside a build directory:
cmake_minimum_required(VERSION 2.8)
project(MEX)
enable_language(Fortran)
find_package(Matlab REQUIRED MAIN_PROGRAM MX_LIBRARY)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin/")
# Assuming gfortran
set(CMAKE_Fortran_FLAGS "-c -fpic -Wall -O3 -fopenmp -fdefault-real-8 -fdefault-double-8")
include_directories(
${Matlab_INCLUDE_DIRS}
)
# Add modules with MEX to be built
add_subdirectory("${PROJECT_SOURCE_DIR}/Project1")
And inside the Project1 directory I have, another CMakeLists.txt:
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
## MEX functions
matlab_add_mex(
NAME mex_executable
SRC mex_executable.F *.f
)
target_link_libraries(mex_executable lgfortran liomp5 lirc lsvml limf )
When I run the CMake I get the error:
Cannot find source file:
*.f
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
What is the correct way to tell CMake to compile the Fortran files and link the correct mex libraries?
This error likely results from the arguments provided to the matlab_add_mex() command here:
matlab_add_mex(
NAME mex_executable
SRC mex_executable.F *.f
)
The SRC argument accepts a list of source files, and likely cannot resolve the *.f provided. It would be best to list each file individually:
matlab_add_mex(
NAME mex_executable
SRC mex_executable.F file_a.f file_b.f
)
Or, you can use CMake's GLOB to create a list of .f source files, and use that list instead:
file(GLOB FORTRAN_SRCS_LIST *.f)
matlab_add_mex(
NAME mex_executable
SRC mex_executable.F ${FORTRAN_SRCS_LIST}
)
Related
I have received a code written in Fortran with files named using extension .f95. I know that this extension is not recommended, one should only use .f for fixed form Fortran and .f90 for free form Fortran, but this is the way I received the code.
I have prepared some cmake files in order to compile it. It works well when I use gfortran but it does not when I use Intel Fortran 2021. It seems that Intel Fortran does not accept .f95 extensions by default.
For example, the following does not work:
ifort mySrc.f95 -c
But one can force ifort to accept this .f95 extension by typing:
ifort -free -Tf mySrc.f95 -c
This is a simplified CMakeLists.txt I have prepared for the project:
cmake_minimum_required(VERSION 3.12)
project (Test VERSION 1.0
DESCRIPTION "CMAKE files to compile test"
LANGUAGES Fortran)
if (CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "20")
message(FATAL_ERROR "Intel Fortran Compiler 20 or newer required")
endif()
set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -warn all")
set (CMAKE_Fortran_FLAGS_RELEASE "-O2")
set (CMAKE_Fortran_FLAGS_RELWITHDEBINFO "-O2 -g")
set (CMAKE_Fortran_FLAGS_DEBUG "-g")
endif()
file(GLOB FILES_SRC CONFIGURE_DEPENDS "*.f95")
set(LIB_MOD_DIR ${CMAKE_CURRENT_BINARY_DIR}/mod/)
add_executable(MYCODE ${FILES_SRC})
set_target_properties(MYCODE
PROPERTIES Fortran_MODULE_DIRECTORY ${LIB_MOD_DIR})
set_property(TARGET MYCODE PROPERTY LINKER_LANGUAGE Fortran)
install(TARGETS MYCODE
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
)
install(DIRECTORY ${LIB_MOD_DIR} DESTINATION include)
I am trying to add these -free and -Tf options to my cmake scripts, but these options must go right before the filename of the file to compile. I have found this link where they mention that this can be achieved my modifying file /Modules/Platform/Linux-Intel-Fortran.cmake. However, I do not have privileges to modify that file. I have tried adding the following to my CMakeLists.txt right after the endif():
SET(CMAKE_Fortran_COMPILE_OBJECT "<CMAKE_Fortran_COMPILER> -o <OBJECT> <DEFINES> <FLAGS> -c -Tf <SOURCE>")
but I keep getting errors. Is it possible to implement this using the CMakeLists.txt file? Thanks in advance.
When I was adding the following option in the CMakeLists.txt file:
SET(CMAKE_Fortran_COMPILE_OBJECT "<CMAKE_Fortran_COMPILER> -o <OBJECT> <DEFINES> <FLAGS> -c -Tf <SOURCE>")
I forgot to add -free to indicate that the files are in free form format. By default -Tf will treat files as fixed-form Fortran. That was why compilation was failing. So using CMAKE_Fortran_COMPILE_OBJECT was the proper way to go to make ifort accept f95 files.
So now I am able to use cmake with ifort and f95 files. The CMakeLists.txt section for Intel Fortran is the following:
if (CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "20")
message(FATAL_ERROR "Intel Fortran Compiler 20 or newer required")
endif()
set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -warn all")
set (CMAKE_Fortran_FLAGS_RELEASE "-O2")
set (CMAKE_Fortran_FLAGS_RELWITHDEBINFO "-O2 -g")
set (CMAKE_Fortran_FLAGS_DEBUG "-g")
set (CMAKE_Fortran_COMPILE_OBJECT "<CMAKE_Fortran_COMPILER> -o <OBJECT> <DEFINES> <FLAGS> -c -free -Tf <SOURCE>")
endif()
Thank you both for your suggestions.
I have some codebase which has cmake build system .while building iam getting an error as below
/usr/bin/ld: cannot find -lcurl
below is the sample cmakelist.txt
cmake_minimum_required(VERSION 2.8.6)
project(oci_object_test)
set(IB_HOME /home/user/sample_cmake/usr/lib)
include_directories(${LIB_HOME}/include)
link_directories(${LIB_HOME}/lib64)
link_directories(/home/user/sample_cmake/usr/lib/lib64)
link_directories(/home/user/)
set(SOURCES
sample.cpp
)
add_executable(demo ${SOURCES})
target_link_libraries(demo curl openssl)
for the above cmakelist.txt below is the link.txt generated by cmake
/usr/bin/c++ CMakeFiles/demo.dir/sample.cpp.o -o demo -L/home/user/sample_cmake/usr/lib/lib64 -L/home/user -rdynamic -lcurl -lopenssl -Wl,-rpath,/home/user/sample_cmake/usr/lib/lib64:/home/user
this issue is due to -lcurl getting added in link.txt generated by cmake . if i remove -lcurl from link.txt manually and build ,build will get success with no linker error . So is there any way i can get rid off this -lcurl in link.txt or is it possible to define -lcurl path where it actual libcurl present ( for example suppose libcurl present inside /usr/curl_path/curl) so that cmake could generate link.txt as below?
/usr/bin/c++ CMakeFiles/demo.dir/sample.cpp.o -o demo -L/home/user/sample_cmake/usr/lib/lib64 -L/home/user -rdynamic /usr/curl_path/curl -lopenssl -Wl,-rpath,/home/user/sample_cmake/usr/lib/lib64:/home/user
i know i can define libucrl path directly as below which will solve my issue ,
target_link_libraries(demo /usr/curl_path/curl openssl)
but iam looking for something like SET or any other cmake environment variable which i can define inside toolchain.cmake file so that cmakelist.txt is untouched ,in simple words how do i specify those libraries's path to cmake which are going use inside target_link_libraries
If your CMake version is less than 3.12, you need to use this old method. See:
https://cmake.org/cmake/help/v3.10/module/FindCURL.html
cmake_minimum_required(VERSION 3.10)
project(program)
find_package(CURL REQUIRED)
if (CURL_FOUND)
add_executable(program main.cpp)
target_link_libraries(program ${CURL_LIBRARIES})
target_include_directories(program PRIVATE ${CURL_INCLUDE_DIRS})
endif()
There is a new method for CMake 3.12 and later using imported targets. See the new alternative FindCurl.
cmake_minimum_required(VERSION 3.12)
project(program)
find_package(CURL REQUIRED)
if (CURL_FOUND)
add_executable(program main.cpp)
target_link_libraries(program CURL::libcurl)
endif()
I found out that this issue can be solved by two methods (first method is similar to this)
second method is by adding below two lines of code to your cmakelist.txt file before calling target_link_directories
add_library( curl SHARED IMPORTED)
set_property(TARGET curl PROPERTY IMPORTED_LOCATION "${CURL_LIBRARY}")
where CURL_LIBRARY is the path for libcurl.so specified in toolchain.cmake
unfortunately i didn't find any solution to solve this issue without touching cmakelist.txt.
I make my own example following this. But I don't want to make library, but just generate header and source files from .proto file.
So, I just change:
CMakeLists.txt
PROJECT(rpc)
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
SET(CMAKE_CXX_FLAGS "-g -Wall -Werror -std=c++11")
ADD_SUBDIRECTORY(proto)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
ADD_EXECUTABLE(main main.cpp)
#TARGET_LINK_LIBRARIES(main proto ${PROTOBUF_LIBRARY})
TARGET_LINK_LIBRARIES(main ${PROTOBUF_LIBRARY}) #<==== I changed here
proto/CMakeLists.txt
INCLUDE(FindProtobuf)
FIND_PACKAGE(Protobuf REQUIRED)
INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER message.proto)
#ADD_LIBRARY(proto ${PROTO_HEADER} ${PROTO_SRC}) #I don't compile lib anymore
But it doesn't generate header and source files from .proto. So it cannot compile. I think when using add_subdirectory, it doesn't run command protobuf_generate_cpp. Any idea is appreciated.
You can either add ${PROTO_HEADER} ${PROTO_SRC} directly to ADD_EXECUTABLE(main) call or add the following line to proto/CMakeLists.txt:
add_custom_target(gen_proto ALL DEPENDS ${PROTO_HEADER} ${PROTO_SRC})
I'm trying to build a project (with CLion) with the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(alfa_1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c11 -Wall -Wextra -lm")
set(SOURCE_FILES
src/foo.h
src/foo.c
src/bar.h
src/bar.c
src/parser.h
src/parser.c)
add_executable(alfa_1 ${SOURCE_FILES})
In foo.c I use pow() function from math.h, which I include in foo.h. And obviously foo.h is included in foo.c. In bar.c I have main that is doing nothing. Now, standard command line compilation like this
gcc -o bar bar.c bar.h foo.h foo.c -lm
works fine but building the project yields undefined reference to pow. As one can see I included -lm flag in CmakeLists.txt file, so I don't get why this linking part is not working here
CMAKE_CXX_FLAGS are flags for the C++ compiler. -l is a linker flag. To link to a library, use this:
target_link_libraries(alfa_1 m)
You might also want to replace -std=c11 with use of CMAKE_C_STANDARD and related variables (CMAKE_C_STANDARD_REQUIRED, CMAKE_C_EXTENSIONS), and possibly replace use of CMAKE_CXX_FLAGS with a call to target_compile_options().
add the link of library in the cmakeList
add_library(math STATIC path/to/file.cpp)
add_executable(cmake_hello main.cpp)
target_link_libraries(cmake_hello math)
and in the class cpp
#include "path/to/file.hpp"
for mode detaills see this link
In Clion this configuration solved my problem:
cmake_minimum_required(VERSION 3.13)
project(K_Nearest C)
set(CMAKE_C_STANDARD 99)
add_executable(K_Nearest main.c point.h point.c group.c group.h)
target_link_libraries(K_Nearest m)
The important step was: target_link_libraries(K_Nearest m), it should come after add_executable(...) statement.
I have a CMake script where the final executable is linked with my own linker script:
cmake_minimum_required(VERSION 3.1)
project(test_app)
set(LINKER_SCRIPT "linker.ld")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T ${LINKER_SCRIPT}")
add_executable(${PROJECT_NAME}.elf
main.cpp
startup.cpp
)
How do I make an executable dependent also on the linker script file (trigger linking if linker.ld was changed)?
You can add a LINK_DEPENDS property to your executable target, using set_target_properties. Add the following line after your add_executable command:
set_target_properties(${TARGET_NAME} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT})
The first argument to set_target_properties is the target name, i.e. the first argument you passed to add_executable.
I found this mail which described three possible ways for forcing an executable to be dependent on a linker script. Its author prefers this way:
CMakeLists.txt:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(LINKERSCRIPT C)
FILE(WRITE main.c "void main(){}")
# dummy.c must exist:
ADD_EXECUTABLE(EXE main.c dummy.c)
# linkerscript must exist:
SET_SOURCE_FILES_PROPERTIES(
dummy.c PROPERTIES OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/linkerscript
)
Here dummy.c is an empty file, which is listed for the add_executable() command only for make resulted executable dependent on the linker script via the OBJECT_DEPENDS property.