How do I force cmake to include "-pthread" option during compilation? - gcc

I know there is something like find_package(Threads) but it doesn't seem to make a difference (at least by itself). For now I'm using SET(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-pthread"), but it doesn't look like a correct solution to me.

The Threads module in the latest versions (>= 3.1) of CMake generates the Threads::Threads imported target. Linking your target against Threads::Threads adds all the necessary compilation and linking flags. It can be done like this:
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
add_executable(test test.cpp)
target_link_libraries(test Threads::Threads)
Use of the imported target is highly recommended for new code, according to the CMake docs

find_package( Threads ) calls a CMake module that first, searches the file system for the appropriate threads package for this platform, and then sets the CMAKE_THREAD_LIBS_INIT variable (and some other variables as well). It does not tell CMake to link any executables against whatever threads library it finds. You tell CMake to link you executable against the "Threads" library with the target_link_libraries() command. So, for example lets say your program is called test. To link it against threads you need to:
find_package( Threads )
add_executable( test test.cpp )
target_link_libraries( test ${CMAKE_THREAD_LIBS_INIT} )

How about the following:
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
if(CMAKE_USE_PTHREADS_INIT)
set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-pthread")
elseif(...)
...
endif()
add_executable( test test.cpp )
target_link_libraries( test ${CMAKE_THREAD_LIBS_INIT} )

If I explicitly specify the default entry point and the library to use, it compiles without problems. The default entry point here is to specify the version in cmake.
cmake_minimum_required(...), target_link_libraries(...)
Below is an example.
# important
cmake_minimum_required(VERSION 2.8)
project(main)
# set c++ version & etc...
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# important
find_package( Threads )
add_executable(main main.cpp)
# important
target_link_libraries(main ${CMAKE_THREAD_LIBS_INIT})

Related

How to add in a CMake project a global file extension (*.pde) to GCC which is treated like C++ code

I have a very simple CMake script. Unfortunately, the project uses a *.pde file which is plain C++ or C code.
CMake is working with any file ending, but I get a compiler error, because GCC does not know how to handle it. How can I add a global file extension to GCC, so that the *.pde file is compiled as a usual *.cpp file?
The -x c++ foo.pde command is nice if I want to use the console, but for CMake it is (I think) not applicable.
cmake_minimum_required(VERSION 2.8)
project(RPiCopter)
SET( RPiCopter
absdevice
containers
device
exceptions
navigation
frame
vehicle
receiver
scheduler
tinycopter.pde
)
message( STATUS "Include ArduPilot library directories" )
foreach( DIR ${AP_List} ${AP_List_Linux} ${AP_Headers} )
include_directories( "../libraries/${DIR}" )
endforeach()
include_directories( zserge-jsmn )
# ***************************************
# Build the firmware
# ***************************************
add_subdirectory ( zserge-jsmn )
#set(CMAKE_CXX_FLAGS "-x c++ *.pde")
ADD_EXECUTABLE ( RPiCopter ${RPiCopter} )
target_link_libraries ( RPiCopter -Wl,--start-group ${AP_List} ${AP_List_Linux} jsmn -Wl,--end-group )
You should be able to use set_source_files_properties along with the LANGUAGE property to mark the file(s) as C++ sources:
set_source_files_properties(${TheFiles} PROPERTIES LANGUAGE CXX)
As #steveire pointed out in his own answer, this bug will require something like the following workaround:
set_source_files_properties(${TheFiles} PROPERTIES LANGUAGE CXX)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_definitions("-x c++")
endif()
Normally you should be able to just extend CMAKE_CXX_SOURCE_FILE_EXTENSIONS. This would help, if you have a lot of files with unknown file extensions.
But this variable is not cached - as e.g. CMAKE_CXX_FLAGS is - so the following code in CMakeCXXCompiler.cmake.in will always overwrite/hide whatever you will set:
set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;mm;CPP)
I consider this non-caching being a bug in CMake, but until this is going to be changed I searched for a workaround considering the following:
You normally don't want to change files in your CMake's installation
It won't have any effect if you change CMAKE_CXX_SOURCE_FILE_EXTENSIONS after project()/enable_language() (as discussed here).
I have successfully tested the following using one of the "hooks"/configuration variables inside CMakeCXXCompiler.cmake.in:
cmake_minimum_required(VERSION 2.8)
set(CMAKE_CXX_SYSROOT_FLAG_CODE "list(APPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS pde)")
project(RPiCopter CXX)
message("CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${CMAKE_CXX_SOURCE_FILE_EXTENSIONS}")
add_executable(RPiCopter tinycopter.pde)
I decided to use this approach. I just remove the file ending by cmake in the temporary build directory.
So GCC is not confused anymore because of the strange Arduino *.pde file extension.
# Exchange the file ending of the Arduino project file
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tinycopter.pde ${CMAKE_CURRENT_BINARY_DIR}/tinycopter.cpp)
CMake doesn't do this for you:
http://public.kitware.com/Bug/view.php?id=14516

How to use CMake RPath for boost.Python

I'm writing a Python extension module in C++ using Boost.Python. However, I
would like to use a newer version of the Boost library than the system
installation offers. This newer version of boost is contained in
BOOST_ROOT=$HOME/opt/boost/1.55.0.
Following this guide on how
to use RPath in CMake I came up with the following CMakeLists.txt.
cmake_minimum_required(VERSION 2.8)
project("test")
set(PROJECT_DESC "Test Boost.Python")
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
add_definitions(-std=c++11 -Wall -Wextra -pedantic)
find_package(PythonInterp REQUIRED)
find_package(PythonLibsNew REQUIRED)
find_package(Boost COMPONENTS python REQUIRED)
message(STATUS "Using Boost installation in:")
message(STATUS " INCLUDE: ${Boost_INCLUDE_DIRS}")
message(STATUS " LIB: ${Boost_LIBRARIES}")
include_directories(
${PROJECT_SOURCE_DIR}
${PYTHON_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
)
macro(add_python_module _name _srccpp)
PYTHON_ADD_MODULE(${_name} ${_srccpp})
target_link_libraries(${_name} ${Boost_LIBRARIES})
endmacro()
add_python_module(ownership ownership.cpp)
Then I run the following commands to build the module
mkdir build; cd build
cmake -DCMAKE_INSTALL_PATH="$BOOST_ROOT/lib" ..
make
The status message after running cmake points to the right boost
installation. (The CMake boost module picks up the environment variable
$BOOST_ROOT) I.e. the CMake variable Boost_LIBARIES points to
$BOOST_ROOT/lib/libboost_python.so.
But, if I check which libraries would actually be used, the system libraries
are listed:
$ ldd ownership.so
# ...
libboost_python.so.1.53.0 => /usr/lib64/libboost_python.so.1.53.0 (0x00007f09abfc1000)
# ...
This is version 1.53, even though the status message above explicitely pointed
to 1.55.
What am I doing wrong? How can I get ldd to pick the library in
$BOOST_ROOT/lib/libboost_python.so.1.55.0?
First of all as I already mentioned in commens you don't need to use CMake RPATH-manipulations
options. Example: http://pastebin.com/UDyYbQ1d, output: standard and custom
Do you know of a way of convincing CMake otherwise even if LIBRARY_PATH is set
This issue is not related to CMake, it's compiler responsibility. Read this discussion.
Solution
You can clear LIBRARY_PATH if you set BOOST_ROOT variable explicitly. And you can check
environment variable in CMakeLists.txt to avoid this problem in future:
string(COMPARE NOTEQUAL "$ENV{LIBRARY_PATH}" "" library_path_warning)
if(library_path_warning)
message(
WARNING
"LIBRARY_PATH environment variable is not empty ($ENV{LIBRARY_PATH}) "
"This may cause dynamic linking errors!"
)
endif()

How to force cmake not to find mpicxx but only mpicc

I am trying to use cmake to generate Makefile for a MPI program. The issue I have is that I only have mpicc installed (working correctly) the mpicxx is in the PATH but is from an other installation (there are multiple MPIs installed on my system). I don't want to use mpicxx but only mpicc (and the include files and libraries of mpicc).
Bellow is a somewhat hardcoded effort and it works
cmake_minimum_required(VERSION 2.8)
PROJECT(mympihello)
ADD_EXECUTABLE(hellompi hellompi.c)
SET(CMAKE_C_COMPILER mpicc)
target_link_libraries(hellompi /export/home2/SEECS/bibrak/work/programs/installs/mpich3/include)
Following is the generic way (as far as I know) and I want to use this approach but forcing not to use mpicxx (not finding it, discarding mpicxx)
cmake_minimum_required(VERSION 2.8)
PROJECT(mympihello)
ADD_EXECUTABLE(hellompi hellompi.c)
# Require MPI for this project:
find_package(MPI REQUIRED)
set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} ${MPI_COMPILE_FLAGS})
set(CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS} ${MPI_LINK_FLAGS})
include_directories(MPI_INCLUDE_PATH)
target_link_libraries(hellompi ${MPI_LIBRARIES})
Furthermore, it will be helpful to point me towards how to generate .so (shared library) for such programs that use MPI.
Thanks
Some how I managed to do it. Here is my solution to generating .so (shared library) using cmake but only using mpicc not mpicxx
cmake_minimum_required(VERSION 2.8)
project(projectname C)
SET( SOURCE_FILES
sourcefile1.c
sourcefile2.c
sourcefile3.c
)
ADD_LIBRARY(projectname SHARED ${SOURCE_FILES})
find_package(MPI)
if(MPI_FOUND)
set(CMAKE_C_COMPILE_FLAGS ${CMAKE_C_COMPILE_FLAGS} ${MPI_C_COMPILE_FLAGS})
set(CMAKE_C_LINK_FLAGS ${CMAKE_C_LINK_FLAGS} ${MPI_C_LINK_FLAGS})
include_directories(${MPI_C_INCLUDE_PATH})
endif(MPI_FOUND)
target_link_libraries(projectname ${MPI_C_LIBRARIES})
This generates a Makefile that creates projectname.so shared library.

CMake and Boost

I've searched and found out that a lot of people have the same problem, but no solution exists.
I'm using CMake to generate Makefiles for MinGW and when compiling I'm getting an error:
CMakeFiles\boosttest.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x5e): undefined reference to `_imp___ZN5boost6thread4joinEv'
CMakeFiles\boosttest.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x71): undefined reference to `_imp___ZN5boost6threadD1Ev'
CMakeFiles\boosttest.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x88): undefined reference to `_imp___ZN5boost6threadD1Ev'
This seems to be a linking problem, I get it. My CMake configuration is:
project(boosttest)
cmake_minimum_required(VERSION 2.6)
include_directories(${boosttest_SOURCE_DIR}/include c:/boost_1_48_0/)
link_directories(c:/boost_1_48_0/lib)
file(GLOB_RECURSE cppFiles src/*.cpp)
add_executable(boosttest ${cppFiles})
target_link_libraries(boosttest libboost_thread-mgw46-mt-1_48.a)
First I tried using find_package(Boost COMPONENTS thread) and it was working the same way, so I thought to try to do this manually and I still get the same error.
Any insights on this?
I've compiled it for mingw using bjam and as a static link. Also tried doing:
add_library(imp_libboost_thread STATIC IMPORTED)
set_property(TARGET imp_libboost_thread PROPERTY IMPORTED_LOCATION c:/boost_1_48_0/lib/libboost_thread-mgw46-mt-1_48.a)
target_link_libraries(boosttest imp_libboost_thread)
And I still get the same error messages.
For mingw32 you may add definition BOOST_THREAD_USE_LIB. And linking with boost::thread will work. Also you may need Threads package (but i'm not sure, may be it needs only for *nix platforms).
Here is part of my CMakeLists. I copied it from project, which uses boost::thread, and compiles under mingw-gcc (and other compilers):
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_ADDITIONAL_VERSIONS "1.44" "1.44.0")
find_package(Boost COMPONENTS thread date_time program_options filesystem system REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
find_package(Threads REQUIRED)
#...
if (WIN32 AND __COMPILER_GNU)
# mingw-gcc fails to link boost::thread
add_definitions(-DBOOST_THREAD_USE_LIB)
endif (WIN32 AND __COMPILER_GNU)
#...
target_link_libraries(my_exe
${CMAKE_THREAD_LIBS_INIT}
#...
${Boost_LIBRARIES}
)
In my opinion, this question is similar to this question and this one. My best guess would be that you need the same resolution as in my answer to the first question.
I would strongly recommend the use of find_package (Boost ) and take care with the auto-linking:
project(boosttest)
cmake_minimum_required(VERSION 2.6)
# Play with the following defines
# Disable auto-linking.
add_definition( -DBOOST_ALL_NO_LIB )
# In case of a Shared Boost install (dlls), you should then enable this
# add_definitions( -DBOOST_ALL_DYN_LINK )
# Explicitly tell find-package to search for Static Boost libs (if needed)
set( Boost_USE_STATIC_LIBS ON )
find_package( Boost REQUIRED COMPONENTS thread )
include_directories( ${Boost_INCLUDE_DIRS} )
file(GLOB_RECURSE cppFiles src/*.cpp)
add_executable(boosttest ${cppFiles})
target_link_libraries(boosttest ${Boost_LIBRARIES} )

How do you add Boost libraries in CMakeLists.txt?

I need to add Boost libraries into my CMakeLists.txt. How do you do it or how do you add it?
Put this in your CMakeLists.txt file (change any options from OFF to ON if you want):
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.45.0 COMPONENTS *boost libraries here*)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
add_executable(progname file1.cxx file2.cxx)
target_link_libraries(progname ${Boost_LIBRARIES})
endif()
Obviously you need to put the libraries you want where I put *boost libraries here*. For example, if you're using the filesystem and regex library you'd write:
find_package(Boost 1.45.0 COMPONENTS filesystem regex)
You can use find_package to search for available boost libraries. It defers searching for Boost to FindBoost.cmake, which is default installed with CMake.
Upon finding Boost, the find_package() call will have filled many variables (check the reference for FindBoost.cmake). Among these are BOOST_INCLUDE_DIRS, Boost_LIBRARIES and Boost_XXX_LIBRARY variabels, with XXX replaced with specific Boost libraries. You can use these to specify include_directories and target_link_libraries.
For example, suppose you would need boost::program_options and boost::regex, you would do something like:
find_package( Boost REQUIRED COMPONENTS program_options regex )
include_directories( ${Boost_INCLUDE_DIRS} )
add_executable( run main.cpp ) # Example application based on main.cpp
# Alternatively you could use ${Boost_LIBRARIES} here.
target_link_libraries( run ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_REGEX_LIBRARY} )
Some general tips:
When searching, FindBoost checks the environment variable $ENV{BOOST_ROOT}. You can set this variable before calling find_package if necessary.
When you have multiple build-versions of boost (multi-threaded, static, shared, etc.) you can specify you desired configuration before calling find_package. Do this by setting some of the following variables to On: Boost_USE_STATIC_LIBS, Boost_USE_MULTITHREADED, Boost_USE_STATIC_RUNTIME
When searching for Boost on Windows, take care with the auto-linking. Read the "NOTE for Visual Studio Users" in the reference.
My advice is to disable auto-linking and use cmake's dependency handling: add_definitions( -DBOOST_ALL_NO_LIB )
In some cases, you may need to explicitly specify that a dynamic Boost is used: add_definitions( -DBOOST_ALL_DYN_LINK )
Adapting #LainIwakura's answer for modern CMake syntax with imported targets, this would be:
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.45.0 COMPONENTS filesystem regex)
if(Boost_FOUND)
add_executable(progname file1.cxx file2.cxx)
target_link_libraries(progname Boost::filesystem Boost::regex)
endif()
Note that it is not necessary anymore to specify the include directories manually, since it is already taken care of through the imported targets Boost::filesystem and Boost::regex.
regex and filesystem can be replaced by any boost libraries you need.
May this could helpful for some people. I had a naughty error:
undefined reference to symbol '_ZN5boost6system15system_categoryEv'
//usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0: error adding symbols: DSO missing from command line
There were some issue of cmakeList.txt and somehow I was missing to explicitly include the "system" and "filesystem" libraries. So, I wrote these lines in CMakeLists.txt
These lines are written at the beginning before creating the executable of the project, as at this stage we don't need to link boost library to our project executable.
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
set(Boost_NO_SYSTEM_PATHS TRUE)
if (Boost_NO_SYSTEM_PATHS)
set(BOOST_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../3p/boost")
set(BOOST_INCLUDE_DIRS "${BOOST_ROOT}/include")
set(BOOST_LIBRARY_DIRS "${BOOST_ROOT}/lib")
endif (Boost_NO_SYSTEM_PATHS)
find_package(Boost COMPONENTS regex date_time system filesystem thread graph program_options)
find_package(Boost REQUIRED regex date_time system filesystem thread graph program_options)
find_package(Boost COMPONENTS program_options REQUIRED)
Now at the end of the file, I wrote these lines by considering "KeyPointEvaluation" as my project executable.
if(Boost_FOUND)
include_directories(${BOOST_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
add_definitions(${Boost_DEFINITIONS})
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(KeyPointEvaluation ${Boost_LIBRARIES})
target_link_libraries( KeyPointEvaluation ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_REGEX_LIBRARY} ${Boost_SYSTEM_LIBRARY})
endif()
Try as saying Boost documentation:
set(Boost_USE_STATIC_LIBS ON) # only find static libs
set(Boost_USE_DEBUG_LIBS OFF) # ignore debug libs and
set(Boost_USE_RELEASE_LIBS ON) # only find release libs
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.66.0 COMPONENTS date_time filesystem system ...)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
add_executable(foo foo.cc)
target_link_libraries(foo ${Boost_LIBRARIES})
endif()
Don't forget to replace foo to your project name and components to yours!
I agree with the answers 1 and 2. However, I prefer to specify each library separately. This makes the depencencies clearer in big projects.
Yet, there is the danger of mistyping the (case-sensitive) variable names.
In that case there is no direct cmake error but some undefined references linker issues later on, which may take some time to resolve. Therefore I use the following cmake function:
function(VerifyVarDefined)
foreach(lib ${ARGV})
if(DEFINED ${lib})
else(DEFINED ${lib})
message(SEND_ERROR "Variable ${lib} is not defined")
endif(DEFINED ${lib})
endforeach()
endfunction(VerifyVarDefined)
For the example mentioned above, this looks like:
VerifyVarDefined(Boost_PROGRAM_OPTIONS_LIBRARY Boost_REGEX_LIBRARY)
target_link_libraries( run ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_REGEX_LIBRARY} )
If I had written "BOOST_PROGRAM_OPTIONS_LIBRARY" there would have been an error triggered by cmake and not much later triggered by the linker.
Additional information to answers above for those still having problems.
Last version of Cmake's FindBoost.cmake may not content last
version fo Boost. Add it if needed.
Use -DBoost_DEBUG=0 configuration flag to see info on problems.
See for library naming format. Use Boost_COMPILER and Boost_ARCHITECTURE suffix vars if needed.
If you are using custome boost path, set CMAKE_PREFIX_PATH firstly. So, cmake can find your custome boost.
list(FIND CMAKE_PREFIX_PATH ${CUSTOME_BOOST_DEP_PREFIX} _INDEX)
if (_INDEX EQUAL -1)
list(APPEND CMAKE_PREFIX_PATH ${CUSTOME_BOOST_DEP_PREFIX})
# set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
endif ()
By the way, if you run above code in sub cmake file, should set CMAKE_PREFIX_PATH back to parent scope.
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
If you want find all components of boost, using below code.
find_package(Boost 1.76 COMPONENTS ALL)

Resources