Environment
ubuntu 16.04, gcc 5.4.0, cmake 3.5.1
Question
target_link_libraries(promise pthread)
target_link_libraries(promise -pthread)
target_link_libraries(promise -lpthread)
What's the differences, which is better ?
Problem
promise.cpp
std::promise<int> pr;
auto fut = pr.get_future();
pr.set_value(10); // throw std::exception and terminate
CMakeLists.txt
add_executable(promise promise.cpp)
target_link_libraries(promise pthread)
Solution
Modify CMakeLists.txt slightly.
add_executable(promise promise.cpp)
target_link_libraries(promise -pthread)
I found the answer from here. But I don't know why ?
But, the best solution is portable.
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads)
target_link_libraries(promise Threads::Threads)
All calls are generally wrong. As answered by #vre, you should use find_package(Threads) instead.
But all these calls are effectively the same!
Calls
target_link_libraries(promise pthread)
and
target_link_libraries(promise -lpthread)
are transformed into the same linker's command line: for parameters not starting with -, CMake will add -l automatically (from target_link_libraries documentation):
A plain library name: The generated link line will ask the linker to search for the library (e.g. foo becomes -lfoo or foo.lib).
While calls
target_link_libraries(promise -lpthread)
and
target_link_libraries(promise -pthread)
are translated into different flags, for linking process these flags means the same.
Option -pthread, passed to gcc, would add additional compile definitions. But parameters for target_link_libraries are not used for compilation.
Why using find_package(Threads) is correct
If one uses
set(THREADS_PREFER_PTHREAD_FLAG ON) # Without this flag CMake may resort to just '-lpthread'
find_package(Threads)
a library target Threads::Threads is created, with additional compile and link options -pthread attached to it as an interface.
When use
target_link_libraries(promise Threads::Threads)
CMake automatically propagates interface compile and link options, thus promise target is both compiled and linked with -pthread option.
First, we can use cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON to see the underlying commands of make.
target_link_libraries(promise pthread) and target_link_libraries(promise -lpthread) will result the same link option: -lpthread, like:
/usr/bin/c++ -std=c++11 -rdynamic CMakeFiles/promise.dir/promise.cpp.o -o promise -lpthread
However, target_link_libraries(promise -pthread) will give you -pthread option:
/usr/bin/c++ -std=c++11 -rdynamic CMakeFiles/promise.dir/promise.cpp.o -o promise -pthread
The difference between -pthread and -lpthread is well explained here. In general, you should use -pthread and target_link_libraries(promise -pthread).
btw, clang built binary seems ok with both options.
I would suggest using the modern CMake way by means of imported targets:
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads)
target_link_libraries(promise Threads::Threads)
This does not only add the library dependency, it also sets the compile option and works on almost all platforms. See the answers to the following post for further details:
Difference between -pthread and -pthreads for C/C++ on Ubuntu 14.04
And have a look into the fine documentation of FindThreads.cmake module:
https://cmake.org/cmake/help/v3.11/module/FindThreads.html
Related
I am using CMake and GNU's parallel algorithms and the following code snippet in my CMakeLists.txt:
if (OPENMP_FOUND)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif().
Does that make the following command redundant?
target_link_libraries(MyTarget OpenMP::OpenMP_CXX)?
I have tried to find the answer here but to no avail. Upon printing the output of the above variables using the message command, I see that the last two are empty.
-- OpenMP_CXX_FLAGS are: -fopenmp
-- OpenMP_C_FLAGS are: -Xclang -fopenmp
-- CMAKE_EXE_LINKER_FLAGS are:
-- OpenMP_EXE_LINKER_FLAGS are:
I tried looking up the variable definition here but did not find out anything more. A small test programme using:
__gnu_parallel::for_each
ran in parallel regardless whether I included:
target_link_libraries(MyTarget OpenMP::OpenMP_CXX)
which leads me to conclude that it is not necessary. Is that true?
My gcc is g++-9 (Homebrew GCC 9.3.0_1) 9.3.0.
While the code:
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
will update your C++ compile flags with the proper -fopenmp option, this is an old antiquated approach.
By linking against the provided imported target OpenMP::OpenMP_CXX, you achieve the same effect because this target provides the -fopenmp compile option in its INTERFACE_COMPILE_OPTIONS property. Likewise, this imported target propagates any dependent OpenMP libraries you may need (depending on the language), which would otherwise require an additional manual step of linking to ${OpenMP_CXX_LIBRARIES}. So, linking directly to the imported target OpenMP::OpenMP_CXX should be the preferred approach; it saves you the extra manual steps and adheres to modern CMake axioms:
target_link_libraries(MyTarget PRIVATE OpenMP::OpenMP_CXX)
Note, the official documentation for the CMake OpenMP Find Module, and the variables/targets it provides, is here.
I get a message 'can not be used when making a shared object; recompile with -fPIC'
I have try other examples and the issue is the same.
I have try
changing from MODULE to SHARED
cmake .. -DCMAKE_CXX_FLAGS=-fPIC
and other variations
this works:
c++ -c -fPIC -I/usr/include/python3.6m ../account.cpp
c++ -shared -Wall -Werror -Wl,--export-dynamic account.o -L/usr/local/lib -lboost_python36 -o account.so
Here is the basic cmake
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(Test)
find_package(PythonInterp REQUIRED)
find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED)
find_package(Boost 1.70.0 COMPONENTS python REQUIRED)
add_library(account SHARED account.cpp)
target_link_libraries(account Boost::python)
target_include_directories(account PRIVATE ${PYTHON_INCLUDE_DIRS})
set_target_properties(account PROPERTIES PREFIX "")
Using: make VERBOSE=1 the output commands are:
c++ -DBOOST_ALL_NO_LIB -Daccount_EXPORTS -I/usr/include/python3.6m -isystem /usr/local/include -fPIC -o CMakeFiles/account.dir/account.cpp.o -c /src/boost_python_example/account.cpp
c++ -fPIC -shared -Wl,-soname,account.so -o account.so CMakeFiles/account.dir/account.cpp.o /usr/local/lib/libboost_python36.a
So the cmake is not getting the same paths and flags, I am learning cmake so Im trying to understand this problem. Clearly the problem is not on actual libs but telling cmake where to find the proper ones.
The solution was quite simple. Comparing both commands what was missing on the cmake command was: --export-dynamic
So I solved using option(BUILD_SHARED_LIBS "Build libraries as shared as opposed to static" ON) interesting enough the comment is needed.
Working solution:
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(Test)
option(BUILD_SHARED_LIBS "Build libraries as shared as opposed to static" ON)
find_package(PythonInterp REQUIRED)
find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED)
find_package(Boost 1.70.0 COMPONENTS python REQUIRED)
add_library(account SHARED account.cpp)
target_link_libraries(account Boost::python)
target_include_directories(account PRIVATE ${PYTHON_INCLUDE_DIRS})
set_target_properties(account PROPERTIES PREFIX "")
Thanks everyone for the comments they lead me to a solution
I am able to successfully compile the below program.
#include <iostream>
#include "boost/log/trivial.hpp"
int main(int, char**)
{
BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
return EXIT_SUCCESS;
}
With the following CMakeFile.
cmake_minimum_required(VERSION 2.8)
project(boost_log CXX)
# we will use static libs
set(Boost_USE_STATIC_LIBS ON)
# Boost::log required Boost version >= 1.54.0
find_package(Boost 1.54.0 REQUIRED COMPONENTS log)
find_package(Threads)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
set(SRC_FILES
src/main.cpp)
add_executable(boost_log ${SRC_FILES})
target_link_libraries(boost_log ${Boost_LIBRARIES} Threads::Threads)
However, if I edit main.cpp and add the following snippet:
#include "boost/log/utility/setup.hpp"
#include "boost/log/utility/setup/from_settings.hpp"
void blah(void)
{
boost::log::settings setts;
boost::log::init_from_settings(setts);
}
Then I get linking errors:
/usr/bin/c++ -rdynamic CMakeFiles/boost_log.dir/src/main.cpp.o -o boost_log -Wl,-Bstatic -lboost_log -lboost_date_time -lboost_log_setup -lboost_system -lboost_filesystem -lboost_thread -lboost_regex -lboost_chrono -lboost_atomic -Wl,-Bdynamic -lpthread -lpthread
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libboost_log_setup.a(init_from_settings.o): In function `boost::log::v2s_mt_posix::(anonymous namespace)::default_syslog_sink_factory<char>::create_sink(boost::log::v2s_mt_posix::basic_settings_section<char> const&)':
(.text+0x27fa): undefined reference to `boost::log::v2s_mt_posix::sinks::syslog_backend::set_severity_mapper(boost::log::v2s_mt_posix::aux::light_function<boost::log::v2s_mt_posix::sinks::syslog::level (boost::log::v2s_mt_posix::record_view const&)> const&)'
(snipped, but the errors continue)
Why does including from_settings.hpp cause linking to fail? Is this not avaliable to link statically?
I have tried both on Fedora and Ubuntu with the same result.
You are missing the log_setup library!
Do:
find_package(Boost 1.54.0 REQUIRED COMPONENTS log_setup log)
I encountered the same link error these days and it turned out to be a static linking order issue which is a topic I'm not familiar enough to explain here but I found an article that may help: Library order in static linking.
I used the same C++ source code as you posted in the question but my CMakeLists.txt looks like the following:
cmake_minimum_required(VERSION 3.10)
include(CMakePrintHelpers)
project(boost_log CXX)
# Compile as C++17.
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# we will use static libs
set(Boost_USE_STATIC_LIBS ON)
find_package(Boost REQUIRED COMPONENTS
filesystem
log
log_setup
regex
system
)
find_package(Threads)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
set(SRC_FILES main.cpp)
message(STATUS "==========")
message(STATUS "Boost_LIBRARIES: ${Boost_LIBRARIES}")
message(STATUS "==========")
add_executable(boost_log_exec ${SRC_FILES}
)
target_link_libraries(boost_log_exec
# Unfortunately, in ${Boost_LIBRARIES}, `boost_log_setup` follows
# `boost_log` rather than precedes it, hence the link errors.
# ${Boost_LIBRARIES}
Boost::log_setup
Boost::log
Threads::Threads
)
The key point is the explicit use of Boost::log_setup and Boost::log in this particular order (i.e., Boost::log_setup must precede Boost::log) which are CMake targets that are explained here. With these two targets explicitly specified in target_link_libraries, you don't need the variable Boost_LIBRARIES at all.
The order of these two is important due to the static linking order issue I mentioned at the very beginning: one must put before the other in order to link correctly.
The reason that ${Boost_LIBRARIES} alone doesn't work is that the static libraries that Boost_LIBRARIES represents are listed in the following order (which is printed out by the message call in my CMakeLists.txt):
Boost_LIBRARIES: /usr/lib/x86_64-linux-gnu/libboost_filesystem.a;/usr/lib/x86_64-linux-gnu/libboost_log.a;/usr/lib/x86_64-linux-gnu/libboost_log_setup.a;/usr/lib/x86_64-linux-gnu/libboost_regex.a;/usr/lib/x86_64-linux-gnu/libboost_system.a;/usr/lib/x86_64-linux-gnu/libboost_date_time.a;/usr/lib/x86_64-linux-gnu/libboost_thread.a;-lpthread;/usr/lib/x86_64-linux-gnu/libboost_chrono.a;/usr/lib/x86_64-linux-gnu/libboost_atomic.a
(I'm not sure why -lpthread is also in the listing, by the way.)
The GCC command line that CMake generates uses the same order of the static libraries when ${Boost_LIBRARIES} was used. Therefore, the actual command was (see note [1] at the end):
/usr/bin/c++ CMakeFiles/boost_log_exec.dir/main.cpp.o -o boost_log_exec /usr/lib/x86_64-linux-gnu/libboost_filesystem.a /usr/lib/x86_64-linux-gnu/libboost_log.a /usr/lib/x86_64-linux-gnu/libboost_log_setup.a /usr/lib/x86_64-linux-gnu/libboost_regex.a /usr/lib/x86_64-linux-gnu/libboost_system.a /usr/lib/x86_64-linux-gnu/libboost_date_time.a /usr/lib/x86_64-linux-gnu/libboost_thread.a -lpthread /usr/lib/x86_64-linux-gnu/libboost_chrono.a /usr/lib/x86_64-linux-gnu/libboost_atomic.a -lpthread
The libboost_log.a and libboost_log_setup.a are listed in the inverse order that they should be, hence the link errors.
In addition, using the CMake target Boost::log itself doesn't solve the problem. In other words, the following code snippet doesn't work:
target_link_libraries(boost_log_exec
Boost::log
Threads::Threads
)
It doesn't work because the target Boost::log also lists libboost_log.a first and then libboost_log_setup.a, which is not the desired order. I found this by showing the underlying GCC command line as I mentioned in note [1].
Note [1]: FYI: After I ran cmake . to configure the build, I ran make VERBOSE=1 to build but also show the underlying GCC command line. New versions of CMake seem to support --verbose command line option directly. See this answer.
I am working on a project were I maintain a CMakeLists.txt file to keep track of the dependencies when I need to compile.
I recently, started using a new library that I need to integrate in my project. The library comes with some examples on how to compile but this is purely a Makefile. I would like to integrate the logic of the Makefile into my project's CMakeLists.txt file.
The Makefile of this library is as follows:
COMMON=-O2 -I/home/john/.mujoco/mjpro200/include -L/home/john/.mujoco/mjpro200/bin -std=c++11 -mavx -pthread -Wl,-rpath,'$$ORIGIN'
all:
g++ $(COMMON) basic.cpp -lmujoco200 -lGL -lglew /home/john/.mujoco/mjpro200/bin/libglfw.so.3 -o basic
gcc -c -O2 -mavx -I/home/john/.mujoco/mjpro200/include /home/john/.mujoco/mjpro200/include/uitools.c
rm *.o
I would like to convert this Makefile into CMakeLists.txt exactly if possible. I see that they provide some flags for threading (pthread) and I want to keep these flags and settings in my CMakeLists.txt in case they are needed for performance.
Here is my CMakeLists.txt:
cmake_minimum_required (VERSION 2.6.0)
project(myproject)
add_compile_options(-std=c++11) # CMake 2.8.12 or newer
if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX )
add_definitions("-fno-strict-aliasing -Wall")
endif( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX )
# optional in case boost is used
find_package(Boost 1.58 EXACT)
find_package(Eigen REQUIRED)
set(mujocoCommon "-O2 -I/home/john/.mujoco/mjpro200/include -L/home/john/.mujoco/mjpro200/bin -std=c++11 -mavx -pthread -Wl,-rpath,'$$ORIGIN'")
set(Mujoco_INCLUDE_DIRS "/home/john/.mujoco/mjpro200/include")
include_directories(${Boost_INCLUDE_DIRS} ${Eigen_INCLUDE_DIRS} ${Mujoco_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
add_executable(myproject mycode.cpp)
install(TARGETS myproject DESTINATION .)
So I tried to define a variable mujocoCommon similar to the COMMON in the Makefile as well as the Mujoco_INCLUDE_DIRS that I then use in the CMake's include_directories.
Note that in the myproject.cpp I have MuJoCo code and other dependencies that I need to correctly link against. In the Makefile things looks a bit more simpler because in there the code has only MuJoco dependencies.
I need some heads-up on how to add in my CMakeLists.txt the following:
-mavx -pthread -Wl,-rpath,'$$ORIGIN' part of Makefile's COMMON variable.
-lmujoco200 -lGL -lglew /home/john/.mujoco/mjpro200/bin/libglfw.so.3
-c -O2 -mavx -I/home/john/.mujoco/mjpro200/include /home/john/.mujoco/mjpro200/include/uitools.c
Currently with the minimal knowledge on CMake and what I have in my CMakeLists.txt when I compile using "make" I get many errors of the kind:
myproject.cpp:(.text+0xfa9): undefined reference to `glfwSetMouseButtonCallback'
Basically I would like to link (?) my code with MuJoco library as is done in their Makefile.
Thanks.
Edit
In regards with the possible duplicate flag, I added the following flag:
set(Mujoco_LIBRARIES "/home/john/.mujoco/mjpro200/bin")
target_link_libraries(myproject ${Mujoco_LIBRARIES} -lboost_system)
But it didn't solved the problem.
Edit 2:
I have also added this one:
set(CMAKE_CXX_FLAGS "-lmujoco200 -lGL -lglew /home/john/.mujoco/mjpro200/bin/libglfw.so.3")
The errors I am getting:
/usr/bin/x86_64-linux-gnu-ld: cannot find -lmujoco200
/usr/bin/x86_64-linux-gnu-ld: cannot find -lglew
You also need to add the opengl libraries to the link libraries, target_link_libraries. Don't add them with -l.
This question already has an answer here:
Flag '-l' in CMAKE_CXX_FLAGS doesn't work
(1 answer)
Closed 4 years ago.
I have a strange behavior where CMake is not able to link any executable if dynamic linking is required. g++ is not able to find any of the symbols defined in the libraries.
I found out it might have to do with the order of the arguments CMake passes to g++ when linking.
Here is the verbose output of the build process (which fails linking):
[ 50%] Building CXX object CMakeFiles/chargen.dir/test.cpp.obj
g++ -std=c++11 -o CMakeFiles/test.dir/test.cpp.obj -c /f/test/test.cpp
[100%] Linking CXX executable mytest
/usr/bin/cmake -E cmake_link_script CMakeFiles/test.dir/link.txt --verbose=1
g++ -std=c++11 -lSDL2 CMakeFiles/test.dir/test.cpp.obj -o mytest
Indeed if I try to link using that command I get undefined references, however if I compile with the library flags at the end:
g++ -std=c++11 CMakeFiles/test.dir/test.cpp.obj -o mytest -lSDL2
it runs just fine. How can I force CMake to use that order of arguments instead?
The contents of the CMakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(mytest)
set(COMPILER_PATH "/usr/bin/")
set(CMAKE_MAKE_PROGRAM "make")
set(CMAKE_C_COMPILER "gcc")
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lSDL2")
set(SOURCE_FILES test.cpp)
add_executable(mytest ${SOURCE_FILES})
You have probably added -lSDL2 into CMAKE_CXX_FLAGS. In that case it will appear withn compile/link flags, in front of source file name in actual link command, as you showed. Don't do that.
You should use _target_link_libraries_ cmake command in order to define libraries to link against. In brief, the skeleton of your CMakeLists.txt should look like this:
project (project_name)
add_executable (mytest test.cpp)
target_link_libraries( mytest SDL2)
In this case, cmake will put libraries on correct place. Note that you may use target_link_libraries after adding target mytest
[EDIT]
After seeing your CMakeLists it is obvious that your problem is in wrong CMAKE_EXE_LINKER_FLAGS. Simply delete the line where you are setting it, and add target_link_libraries after add_executable.
Regarding your question about handling circular dependencies among static libs, you handle it the sam way as you would if you didn't use cmake: mention it twice:
target_link_libraries(
mytest
circular_dep1
circular_dep2
circular_dep1
circular_dep2
)
regarding your question about specific linker flags, just place them into target_link_libraries command, it accepts linker flags as well. You can find documentation on following link:
https://cmake.org/cmake/help/latest/command/target_link_libraries.html