You should use the CHECK_FUNCTION_EXISTS command to check if pow can be used without additional flags. If this check fails, you can add m library to CMAKE_REQUIRED_LIBRARIES variable, assuming that linking against libm is what's missing. But you'll need to CHECK_FUNCTION_EXISTS again to make sure the linking is sufficient.
Sample code:
include(CheckFunctionExists)
if(NOT POW_FUNCTION_EXISTS AND NOT NEED_LINKING_AGAINST_LIBM)
CHECK_FUNCTION_EXISTS(pow POW_FUNCTION_EXISTS)
if(NOT POW_FUNCTION_EXISTS)
unset(POW_FUNCTION_EXISTS CACHE)
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
CHECK_FUNCTION_EXISTS(pow POW_FUNCTION_EXISTS)
if(POW_FUNCTION_EXISTS)
set(NEED_LINKING_AGAINST_LIBM True CACHE BOOL "" FORCE)
else()
message(FATAL_ERROR "Failed making the pow() function available")
endif()
endif()
endif()
if (NEED_LINKING_AGAINST_LIBM)
target_link_libraries(your_target_here m)
endif()
Answer from arrowd on Stack OverflowYou should use the CHECK_FUNCTION_EXISTS command to check if pow can be used without additional flags. If this check fails, you can add m library to CMAKE_REQUIRED_LIBRARIES variable, assuming that linking against libm is what's missing. But you'll need to CHECK_FUNCTION_EXISTS again to make sure the linking is sufficient.
Sample code:
include(CheckFunctionExists)
if(NOT POW_FUNCTION_EXISTS AND NOT NEED_LINKING_AGAINST_LIBM)
CHECK_FUNCTION_EXISTS(pow POW_FUNCTION_EXISTS)
if(NOT POW_FUNCTION_EXISTS)
unset(POW_FUNCTION_EXISTS CACHE)
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
CHECK_FUNCTION_EXISTS(pow POW_FUNCTION_EXISTS)
if(POW_FUNCTION_EXISTS)
set(NEED_LINKING_AGAINST_LIBM True CACHE BOOL "" FORCE)
else()
message(FATAL_ERROR "Failed making the pow() function available")
endif()
endif()
endif()
if (NEED_LINKING_AGAINST_LIBM)
target_link_libraries(your_target_here m)
endif()
If I understand correctly, linking libm is always preferred if it is exists.
So, CheckLibraryExists works.
CMakeLists.txt
set(POW_LIBS "")
include(CheckLibraryExists)
check_library_exists(m pow "" LIBM)
if(LIBM)
list(APPEND POW_LIBS "m")
endif()
...
target_link_libraries(${PROJECT_NAME} PUBLIC ${POW_LIBS})
tested with Linux x86_64, glibc 2.23 cmake 3.13.2
Linking a lib file in cmake
How to link to the C math library with CMake? - Stack Overflow
How to statically link external library by target_link_libraries()?
c++ - How to properly link libraries with cmake? - Stack Overflow
Videos
Many mathematical functions (pow, sqrt, fabs, log etc.) are declared in math.h and require the library libm to be linked. Unlike libc, which is automatically linked, libm is a separate library and often requires explicit linkage. The linker presumes all libraries to begin with lib, so to link to libm you link to m.
You have to use it like target_link_libraries(ch4 m) to link libmto your target. The first argument must be a target. Thus it must be used after add_executable(ch4 ch4.c) like:
add_executable(ch4 ch4.c)
target_link_libraries(ch4 m)
I am frankly a bit surprised that this kind of question still doesn't have a proper answer for Modern CMake. These days, the recommended (and portable) approach is this:
find_library(MATH_LIBRARY m)
if(MATH_LIBRARY)
target_link_libraries(MyTarget PUBLIC ${MATH_LIBRARY})
endif()
I've been working on my first larger project which is starting to expand fast, in terms of number of files and sub-directories. I've been trying to use CMake to mostly automate the building process, but right now I feel like I am having to repeat myself quite a bit in the head CMake file when it comes to library linking. For each library and executable I have to first use LINK_LIBRARIES and then use TARGET_LINK_LIBRARIES. If I leave out the first highlighted section (between the #--- sections in the Head CMake file below) the libraries in my src directory do not link properly and if I leave out the TARGET_LINK_LIBRARIES the executables fail to link properly. I am requiring cmake verion 3.0.0.
If this is the way it is supposed to work, then it is what it is; however, while looking this up, I've seen many CMake projects which do not have to link in this way. I'd appreciate any input, even outside of the scope of this question, as this is my first real time using CMake on a large project.
I've included a shortened version of my working tree, the template I've used for creating libraries in src subdirectories, and how the tests are generated.
Head CMake File, shortened to remove Release/debug support, project information, etc.
LINK_LIBRARIES(stdc++fs tinyxml2 sqlite3 spdlog fmt)
INCLUDE_DIRECTORIES(thirdparty/include $ENV{MSYS2INCLUDE} include src/UI/Base)
FIND_PACKAGE(wxWidgets REQUIRED COMPONENTS net core base html ribbon)
FIND_PACKAGE(Threads)
ADD_COMPILE_DEFINITIONS(SPDLOG_FMT_EXTERNAL)
ADD_COMPILE_OPTIONS( --LOTS OF WARNINGS)
INCLUDE(${wxWidgets_USE_FILE})
# ------------------------------------------------------
LINK_LIBRARIES(${wxWidgets_LIBRARIES} Threads::Threads)
# ------------------------------------------------------
ADD_SUBDIRECTORY(thirdparty)
ADD_SUBDIRECTORY(src)
ADD_SUBDIRECTORY(tests)
ADD_EXECUTABLE(XMLTags xmltagextractor.cpp)
ADD_EXECUTABLE(CreatorUI capp.cpp)
# ------------------------------------------------------
TARGET_LINK_LIBRARIES(CreatorUI CreatorBase ThirdParty UI Threads::Threads
UI_BASE ${wxWidgets_LIBRARIES} Creator )
TARGET_LINK_LIBRARIES(XMLTags CreatorBase ThirdParty Creator )
# ------------------------------------------------------I've shortened it to make it easier to glance at but this is my current working tree
.
| CMakeLists.txt // Head CMake file, Builds CAPP and xmlTagExtractor
| capp.cpp // Main exe file 1
| capp.hpp
| xmltagextractor.cpp // Main exe file 2
|
+---include // Include directory for projects .h and .hpp files
| +---Creator
| | | DescriptionTools.hpp
| | |
| | \---Base
| | CreatorFactory.hpp
| | LoggingTools.hpp
| | etc.
| |
| \---UI
| primativeDesign.hpp
|
+---src // files to be compiled into libraries
| | CMakeLists.txt // Adds Creator and UI subdirectories
| |
| +---Creator // Makes Creator library, see template 1
| | | CMakeLists.txt
| | | DescriptionTools.cpp
| | | etc.
| | |
| | \---Base // Makes Creator_Base library, see template 1
| | CMakeLists.txt
| | CreatorFactory.cpp
| | etc.
| |
| \---UI // Makes UI library, see template 1
| | CMakeLists.txt
| | primativeDesign.cpp
| | etc.
| |
| \---Base // Makes UIBase Library, see template 1
| baseProject.cpp
| baseProject.h
| CMakeLists.txt
| etc.
|
+---tests // Builds all testing executables, see template 2
| CMakeLists.txt
| ParLoad.cpp
|
\---thirdparty // third party Shortened because this works fine
| CMakeLists.txt
|
\---include
magic_enum.hppCMake Templates:
Template 1: Basic library creation
ADD_SUBDIRECTORY(...) # if required
SET(subname_sources
$all_cpp_files
)
ADD_LIBRARY(subname ${subname_sources})
LINK_LIBRARIES(subname) # link this to the global space
TARGET_LINK_LIBRARIES(subname -required-libs) # link required libs to this lib
# both of these last two lines seem to be requiredTemplate 2: Test Creation (does not register with CMakeTests)
file(GLOB test_sources RELATIVE ${CMAKE_SOURCE_DIR}/tests *.cpp)
foreach(test ${test_sources})
string(REPLACE ".cpp" "" testname ${test})
add_executable(${testname} ${test})
target_link_libraries(${testname} CreatorBase ThirdParty Creator UI ...)
endforeach(test ${test_sources})Thank you!
arrowdodger's answer is correct and preferred on many occasions. I would simply like to add an alternative to his answer:
You could add an "imported" library target, instead of a link-directory. Something like:
# Your-external "mylib", add GLOBAL if the imported library is located in directories above the current.
add_library( mylib SHARED IMPORTED )
# You can define two import-locations: one for debug and one for release.
set_target_properties( mylib PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/res/mylib.so )
And then link as if this library was built by your project:
TARGET_LINK_LIBRARIES(GLBall mylib)
Such an approach would give you a little more flexibility: Take a look at the add_library( IMPORTED) command and the many target-properties related to imported libraries.
I do not know if this will solve your problem with "updated versions of libs".
Set libraries search path first:
link_directories(${CMAKE_BINARY_DIR}/res)
And then just do
target_link_libraries(GLBall mylib)