CMake, shared library linking fail - cmake

I'm currently getting used to cmake and I'm trying to compile a small project with a .so library linking.
My project is the following.
/
CMakeLists.txt
inc/
Als.h
src/
main.c
CMakeLists.txt
lib/
libals.so
build/
I'm compiling from the build directory with:
$ cmake ..
-- DIR:
-- Configuring done
-- Generating done
-- Build files have been written to: /home/julien/tmp/cmakeTest/build
And then:
$ make
Linking C executable cmakeTest
/usr/bin/ld: ne peut trouver -lals
collect2: error: ld returned 1 exit status
src/CMakeFiles/cmakeTest.dir/build.make:85: recipe for target 'src/cmakeTest' failed
make[2]: *** [src/cmakeTest] Error 1
CMakeFiles/Makefile2:75: recipe for target 'src/CMakeFiles/cmakeTest.dir/all' failed
make[1]: *** [src/CMakeFiles/cmakeTest.dir/all] Error 2
Makefile:76: recipe for target 'all' failed
make: *** [all] Error 2
The linker seems to be unable to find the libals.so file.
Here is the file /CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
PROJECT(cmaketest)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
INCLUDE_DIRECTORIES(
inc
)
ADD_SUBDIRECTORY(src)
get_directory_property(OUT_VAR LINK_DIRECTORIES)
message(STATUS "DIR: ${OUT_VAR}")
And here is the file /src/CMakeLists.txt:
PROJECT(cmakeTest)
FILE(
GLOB
${PROJECT_NAME}_Sources
*.c
)
INCLUDE_DIRECTORIES(
inc
inc
)
ADD_EXECUTABLE(
${PROJECT_NAME}
${${PROJECT_NAME}_Sources}
)
LINK_DIRECTORIES(
/home/julien/tmp/cmakeTest/lib/
)
TARGET_LINK_LIBRARIES(
${PROJECT_NAME}
als
pthread
)
Maybe I missed something but if I change the /src/CMakeLists.txt to:
PROJECT(cmakeTest)
FILE(
GLOB
${PROJECT_NAME}_Sources
*.c
)
INCLUDE_DIRECTORIES(
inc
inc
)
ADD_EXECUTABLE(
${PROJECT_NAME}
${${PROJECT_NAME}_Sources}
)
TARGET_LINK_LIBRARIES(
${PROJECT_NAME}
/home/julien/tmp/cmakeTest/lib/libals.so
pthread
)
The compilation is ok. Does someone know why the linker is unable to find libals.so when I'm giving him the good directory path to look in?
The LINK_DIRECTORIES functions seems not to be working.

Besides the solution you already have, and my solution in a comment, the problem you have with the CMake file shown is the order in which you invoke the CMake commands.
From the link_directories command reference:
The command will apply only to targets created after it is called.
[Emphasis mine]
You simply need to call link_directories before you call add_executable.

Related

Issues with linking GLFW to the executable with CMake

I am currently trying to link the GLFW library with my executable files in CLion. After hours of research and trial & error, I am stuck. I am using find_package() to locate my GLFW library. For some reason my FindGLFW.cmake file seems to correctly locate the library in /usr/local/lib/libglfw.a when using find_library(), but my CMakeLists.txt returns empty with find_package(). I don't really understand how that's possible. Could someone help me out?
CMakeLists.txt:
cmake_minimum_required(VERSION 3.15)
project(learnopengl)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMake)
find_package(glfw 3.3 REQUIRED)
message(STATUS "(CMakeLists.txt) GLFW: [${glfw}]")
if (NOT glfw)
message(SEND_ERROR "(CMakeLists) Did not find glfw_library")
endif()
add_executable(learnopengl src/main.cpp)
target_link_libraries(learnopengl glfw)
FindGLFW.cmake
find_library( GLFW_LIBRARY
NAMES
glfw3 glfw
PATHS
${GLFW_LOCATION}/lib
$ENV{GLFW_LOCATION}/lib
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
NO_DEFAULT_PATH
DOC "The GLFW library"
)
message(STATUS "(FindGLFW.cmake) GLFW_INCLUDE_DIR: [${GLFW_INCLUDE_DIR}]")
message(STATUS "(FindGLFW.cmake) GLFW_LIB: [${GLFW_LIBRARY}]")
if (NOT GLFW_LIBRARY)
message(SEND_ERROR "(FindGLFW.cmake) Did not find glfw_library")
Output when running cmake ..
-- (FindGLFW.cmake) GLFW_INCLUDE_DIR: [/usr/local/include]
-- (FindGLFW.cmake) GLFW_LIB: [/usr/local/lib/libglfw3.a]
-- (CMakeLists.txt) GLFW: []
CMake Error at CMakeLists.txt:12 (message):
(CMakeLists) Did not find glfw_library
When I tried to directly include find_library() in my CMakeLists.txt instead, it did locate the library, but when I tried to link it with my executable, I got a linker error saying it couldn't locate the library:
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(learnopengl)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMake)
find_library( GLFW_LIBRARY
NAMES
glfw3 glfw
PATHS
${GLFW_LOCATION}/lib
$ENV{GLFW_LOCATION}/lib
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
NO_DEFAULT_PATH
DOC "The GLFW library"
)
message(STATUS "(FindGLFW.cmake) GLFW_LIB: [${GLFW_LIBRARY}]")
if (NOT GLFW_LIBRARY)
message(SEND_ERROR "(CMakeLists.txt) Did not find glfw_library")
endif()
add_executable(learnopengl src/main.cpp)
target_link_libraries(learnopengl GLFW_LIBRARY)
Output:
~/dev/projects/opengl/learnopengl/build  cmake ..
-- (CMakeLists.txt) GLFW_LIB: [/usr/local/lib/libglfw3.a]
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/Philipp/dev/projects/opengl/learnopengl/build
~/dev/projects/opengl/learnopengl/build  cmake --build .
[ 50%] Linking CXX executable learnopengl
ld: library not found for -lGLFW_LIBRARY
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [learnopengl] Error 1
make[1]: *** [CMakeFiles/learnopengl.dir/all] Error 2
make: *** [all] Error 2
I would really appreciate some hints as to what I am doing wrong. I can't see why it wouldn't locate/link the library correctly.
Thank you!
In cmake, arguments are case sensitive, so find_package should be
find_package(GLFW 3.3 REQUIRED)
Linker problem can be found easily in the logs. You are trying to link -lGLFW_LIBRARY, however what you want to link is GLFW_LIBRARY's value, /usr/local/lib/libglfw3.a .
target_link_libraries(learnopengl ${GLFW_LIBRARY})

multiple definition of 'CGAL::Surface_mesh_parameterization::get_error_message(int)'

I am able to use CGAL surface mesh parametrization with given examples easily. Which means that CGAL is installed properly and is functional.
Ways to reproduce error:
Create a empty main file
Create a class file with appropriate modifications to CGAL square_border_parametrize.cpp
After I do cmake . and make this is the output
Scanning dependencies of target Main
[ 33%] Building CXX object CMakeFiles/Main.dir/SBP.cpp.o
:0:15: warning: missing whitespace after the macro name
:0:15: warning: missing whitespace after the macro name
[ 66%] Building CXX object CMakeFiles/Main.dir/main.cpp.o
:0:15: warning: missing whitespace after the macro name
:0:15: warning: missing whitespace after the macro name
[100%] Linking CXX executable Main
CMakeFiles/Main.dir/main.cpp.o: In function _mm_getcsr()':
/usr/local/include/CGAL/Interval_nt.h:202: multiple definition ofCGAL::Surface_mesh_parameterization::get_error_message(int)'
CMakeFiles/Main.dir/SBP.cpp.o:/usr/local/include/CGAL/Surface_mesh_parameterization/Error_code.h:53: first defined here
collect2: error: ld returned 1 exit status
CMakeFiles/Main.dir/build.make:450: recipe for target 'Main' failed
make[2]: * [Main] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/Main.dir/all' failed
make[1]: * [CMakeFiles/Main.dir/all] Error 2
Makefile:140: recipe for target 'all' failed
make: *** [all] Error 2
I am not able to find any multiple definition for CGAL::Surface_mesh_parameterization::get_error_message(int). My CMakeLists.txt file looks like this:
cmake_minimum_required (VERSION 2.8 FATAL_ERROR)
PROJECT(LSCM)
FIND_PACKAGE( OpenCV REQUIRED )
find_package( PCL 1.7 REQUIRED COMPONENTS common io visualization filters )
find_package( CGAL QUIET COMPONENTS )
if ( NOT CGAL_FOUND )
message(STATUS "This project requires the CGAL library, and will not be compiled.")
return()
endif()
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
include( CGAL_CreateSingleSourceCGALProgram )
find_package( Boost REQUIRED )
if ( NOT Boost_FOUND )
message(STATUS "This project requires the Boost library, and will not be compiled.")
return()
endif()
SET(CMAKE_BUILD_TYPE "Debug")
SET(LIBRARY_OUTPUT_PATH "./lib")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
file(GLOB SOURCE_FILES ./*.cpp)
ADD_EXECUTABLE(Main ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(Main ${OpenCV_LIBS} ${PCL_LIBRARIES} ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} -lCGAL -lm )
install (TARGETS Main DESTINATION ~/bin)
A quick fix: In the file include/CGAL/Surface_mesh_parameterization/Error_code.h write inline in front of const char* get_error_message(int error_code).
The fix is in this pull request, that is now merged in CGAL-4.12.

Adding static dependency in CMake

I've got an example project:
.
├── CMakeLists.txt
└── src
└── test1.f90
where test1.f90 uses a specific version of Lapack (therefore I can't use FindLAPACK).
I am trying to compile this using CMake:
cmake_minimum_required(VERSION 2.5)
project(TEST)
file(GLOB_RECURSE sources src/*.f90)
add_executable(cmake.x ${sources})
enable_language(Fortran)
set(CMAKE_Fortran_COMPILER_ID "IBM")
if(CMAKE_Fortran_COMPILER_ID MATCHES "IBM")
set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS)
MESSAGE(STATUS "IBM")
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,-allow-multiple-definition ")
set(CMAKE_Fortran_COMPILER mpixlf2008_r)
set(debug "-C")
endif()
set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${bounds}")
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${dialect}")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
MESSAGE( STATUS "cmake_module_path: " ${CMAKE_MODULE_PATH})
If I run make VERBOSE=1 this results in:
...
[100%] Building Fortran object CMakeFiles/cmake.x.dir/src/test1.o
mpixlf2008_r -c /work/jias12/jias1217/lapack_test/src/test1.f90 -o CMakeFiles/cmake.x.dir/src/test1.o
** main === End of Compilation 1 ===
1501-510 Compilation successful for file test1.f90.
Linking Fortran executable cmake.x
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmake.x.dir/link.txt --verbose=1
mpixlf2008_r -Wl,-allow-multiple-definition CMakeFiles/cmake.x.dir/src/test1.o -o cmake.x
CMakeFiles/cmake.x.dir/src/test1.o:(.text+0x5c): undefined reference to `sgesv'
make[2]: *** [cmake.x] Error 1
make[2]: Leaving directory `/work/jias12/jias1217/lapack_test'
make[1]: *** [CMakeFiles/cmake.x.dir/all] Error 2
make[1]: Leaving directory `/work/jias12/jias1217/lapack_test'
make: *** [all] Error 2
This obviously doesn't work, because I didn't include LAPACK, which I then can do manually:
mpixlf2008_r -Wl,-allow-multiple-definition CMakeFiles/cmake.x.dir/src/test1.o -o cmake.x -L$LAPACK_LIB -L/bgsys/local/lib -llapack -lesslbg
Which works fine. How can I achieve this using CMake? I want to add -L$LAPACK_LIB -L/bgsys/local/lib -llapack -lesslbg to the linker after the *.o files. All I've managed is to add them as flags before the *.o files, which fails. I've look at a number of examples on the web, but I cannot find something which works in my case. This is the test1.f90.
This is in the folders:
> ls $LAPACK_LIB
libblas_extra.a libcblas.a liblapack.a liblapacke.a libtmglib.a
ls /bgsys/local/lib/
BGeic.pm BG.pm libesslbg.a libesslsmpbg.a
As Tsyvarev correctly mentioned:
What is wrong with target_link_libraries which links with the
libraries (meaning of flag -l) and link_directories which specifies
libraries search path (meaning of flag -L)?
Those hase to be called in the right order, which leads to:
cmake_minimum_required(VERSION 2.5)
project(TEST)
file(GLOB_RECURSE sources src/*.f90)
link_directories($ENV{LAPACK_LIB} /bgsys/local/lib)
enable_language(Fortran)
add_executable(cmake.x ${sources})
target_link_libraries(cmake.x lapack esslbg)

CMake-generated Makefile does not contain target

I'm using G++ MinGW for compiling. My Files :
main.cpp, linkedList.cpp, linkedList.h
My CMake file :
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
project (Tutorial)
set(CMAKE_CXX_FLAGS "-Wall -std=c++11")
enable_testing()
include_directories(include)
add_executable(Tutorial
main.cpp
linkedList.cpp
linkedList.h
)
add_test(Tutorial tutorial)
The exact compile error from generated Makefile :
mingw32-make[2]: *** No rule to make target '../linkedList.h', needed by 'CMakeFiles/Tutorial.dir/main.cpp.obj'. Stop.
mingw32-make[1]: *** [CMakeFiles/Tutorial.dir/all] Error 2
mingw32-make: *** [all] Error 2
Gist for CMake generated Makefile
You target is Tutorial, not ../LinkedList.h
Go to your build directory and execute
make Tutorial

CMake install: installing configuration files

I want CMake to make install rules for me which also automatically install configuration and other things. I looked at this question, but adding:
add_executable(solshare_stats.conf solshare_stats.conf)
to my CMakeLists.txt file only gave me warnings and errors:
CMake Error: CMake can not determine linker language for target:solshare_stats.conf
CMake Error: Cannot determine link language for target "solshare_stats.conf".
...
make[2]: *** No rule to make target `CMakeFiles/solshare_stats.conf.dir/build'. Stop.
make[1]: *** [CMakeFiles/solshare_stats.conf.dir/all] Error 2
make: *** [all] Error 2
How do I add configuration, init and/or logfiles to CMake install rules?
Here is my complete CMakeLists.txt file:
project(solshare_stats)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST} )
add_executable(solshare_stats.conf solshare_stats.conf)
target_link_libraries(solshare_stats mysqlcppconn)
target_link_libraries(solshare_stats wiringPi)
if(UNIX)
if(CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_EXE_LINKER_FLAGS "-s")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall -std=c++0x")
endif()
install(TARGETS solshare_stats DESTINATION /usr/bin COMPONENT binaries)
install(TARGETS solshare_stats.conf DESTINATION /etc/solshare_stats COMPONENT config)
endif()
The .conf file should be included in the add_executable where you define your executable target, not in a separate call:
add_executable(${PROJECT_NAME} ${SRC_LIST} solshare_stats.conf)
Then you need to use install(FILE ...) rather than install(TARGET ...):
install(TARGETS solshare_stats DESTINATION /usr/bin COMPONENT binaries)
install(FILES solshare_stats.conf DESTINATION etc/solshare_stats COMPONENT config)
By doing
add_executable(${PROJECT_NAME} ${SRC_LIST})
add_executable(solshare_stats.conf solshare_stats.conf)
you're saying you want to create 2 executables, one called "solshare_stats" and another called "solshare_stats.conf".
The second target's only source file is the actual file "solshare_stats.conf". Since none of the source files in this target have a suffix which gives an idea about the language (e.g ".cc" or ".cpp" implies C++, ".asm" implies assembler), no language can be deduced, hence the CMake error.