for my project in c++ I wanted to create a cmake file to compile and link everything together.
This is my dir structure so far:
"quadro/minimu9-ahrs" alias home
|-build
|-include
|-src
in my home dir I have this 'CMakeLists.txt' file:
cmake_minimum_required (VERSION 2.6)
project(minimu)
set(HEADER_FILES $("include/*.h")
include_directories(include)
file(GLOB SOURCES "src/*.cpp")
add_executable(minimu ${SOURCES})
add_definitions(-std=c++0x -lwiringPi -lpthread)
#install(TARGETS minimu DESTINATION /usr/lib)
in my 'src' dir I got all the .cpp files, and in 'include' all my headers. When I'm comiling, I go into my build dir, delete everything existing in there (from previous builds) and type
cmake ..
make
my problem in now, that my main.cpp in src uses '#include wiringPi.h', but when I make the project it gives me the following error:
pi#raspberrypi ~/quadro/minimu9-ahrs/build $ make
Scanning dependencies of target minimu
[ 20%] Building CXX object CMakeFiles/minimu.dir/src/L3G.cpp.o
[ 40%] Building CXX object CMakeFiles/minimu.dir/src/LSM303.cpp.o
[ 60%] Building CXX object CMakeFiles/minimu.dir/src/main.cpp.o
[ 80%] Building CXX object CMakeFiles/minimu.dir/src/I2CBus.cpp.o
[100%] Building CXX object CMakeFiles/minimu.dir/src/MinIMU9.cpp.o
Linking CXX executable minimu
CMakeFiles/minimu.dir/src/main.cpp.o: In function `frequency_thread(void*)':
main.cpp:(.text+0x1c): undefined reference to `digitalWrite'
main.cpp:(.text+0x38): undefined reference to `digitalWrite'
CMakeFiles/minimu.dir/src/main.cpp.o: In function `signalHandler(int)':
main.cpp:(.text+0xd4): undefined reference to `digitalWrite'
main.cpp:(.text+0xe8): undefined reference to `digitalWrite'
CMakeFiles/minimu.dir/src/main.cpp.o: In function `main':
main.cpp:(.text+0x14c): undefined reference to `wiringPiSetup'
main.cpp:(.text+0x184): undefined reference to `pinMode'
main.cpp:(.text+0x1e8): undefined reference to `pthread_create'
main.cpp:(.text+0x29c): undefined reference to `pthread_join'
collect2: ld returned 1 exit status
CMakeFiles/minimu.dir/build.make:185: recipe for target 'minimu' failed
make[2]: *** [minimu] Error 1
CMakeFiles/Makefile2:60: recipe for target 'CMakeFiles/minimu.dir/all' failed
make[1]: *** [CMakeFiles/minimu.dir/all] Error 2
Makefile:72: recipe for target 'all' failed
make: *** [all] Error 2
so how do I tell the compiler in cmake where to find and how to use the wiringPi lib? And is there an easier way, instead of deleting everything in my build folder before cmaking? Like it compiles all the 'static' files one time, and only adds the changing file (=main.cpp) everytime again.
Further I want to execute my program everywhere like
sudo minimu
instead of going into the 'build' dir and type
sudo ./minimu
Thanks if you can help me guys!
And sorry if my english isn't that good :)
Have a nice day.
I just figured this out today thanks to Sebastian over at github.
Assuming that you have wiringPi installed, the easiest thing to do is to make a FindWiringPi.cmake with the following:
find_library(WIRINGPI_LIBRARIES NAMES wiringPi)
find_path(WIRINGPI_INCLUDE_DIRS NAMES wiringPi.h)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(wiringPi DEFAULT_MSG WIRINGPI_LIBRARIES WIRINGPI_INCLUDE_DIRS)
And then put this in the folder where cmake looks for it's modules. For Ubuntu it's /usr/share/cmake-2.x/Modules. It's basically the same path for pi too.
Then in your CMakeLists.txt file use:
# Locate libraries and headers
find_package(WiringPi REQUIRED)
find_package(Threads REQUIRED)
# Include headers
include_directories(${WIRINGPI_INCLUDE_DIRS})
# Link against libraries
target_link_libraries(<yourProjectName> ${WIRINGPI_LIBRARIES})
target_link_libraries(<yourProjectName> ${CMAKE_THREAD_LIBS_INIT})
The pthread module is a stock package and should be on your system already. So then navigate to your folder and do a cmake ./ and then make. If this doesn't work the first time, then remove your CMakeCache.txt with rm CMakeCache.txt and try again. MAKE SURE THAT YOU REMOVE THE CACHE AND NOT THE LIST!!
Thanks for the QA, I figured out this can be done in a simpler manner (Raspberry Pi 3 Model B+) without altering anything in /usr/share/cmake-x.y/Modules. After your add_executable line, add the following
find_library(WIRINGPI_LIBRARIES NAMES wiringPi)
target_link_libraries(<executable_name> ${WIRINGPI_LIBRARIES})
For example:
cmake_minimum_required(VERSION 3.5)
project(OpenInsulin)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_VERBOSE_MAKEFILE ON)
# Include headers
include_directories(.)
add_executable(OpenInsulin
main.cpp
MCP9600.cpp
MCP9600.h)
# Link against wiringPi
find_library(WIRINGPI_LIBRARIES NAMES wiringPi)
target_link_libraries(OpenInsulin ${WIRINGPI_LIBRARIES})
Provide a flag -L <path> to compiler flags.
add_definitions(-std=c++0x -L/path/to/libwringPi.???.(so|a) -lwiringPi -lpthread)
I do not understand, why you clear the build dir before running cmake (this is not critique. I really do not understand, There might be a reason I dont know) . make checks if the sources are newer than the last compile output and compiles only the files, that are affected. But this works only, if do not delete the build targets.
To install the resulting program uncomment the install directive in you cmake and setup a target dir that's in you PATH. You can also create a dir /home//bin or so. Prepend it to the PATH environment variable and configure the target of you install directive with the new path. Then, in addition to cmake and make you have to perform a make install.
Related
I am trying to link with a DLL executable using CMake. This works fine on Linux (of course with .so), but on Windows, it seems to be tricky. I thought it might be some other dependencies, so I tried creating a simple test program, but I couldn't get that to work either.
My folder structure is simple:
main.cpp
CmakeLists.txt
lib/libtest.dll
lib/CMakeLists.txt
I based this structure on the answer to another question that was asked.
Unfortunately, when I build, it it fails.
The content of the lib/CMakeLists.txt are:
message("-- Linking Test")
add_library(TEST libtest.dll)
set_target_properties(TEST PROPERTIES LINKER_LANGUAGE C)
And the content of the main CMakeLists.txt are:
cmake_minimum_required(VERSION 3.15)
project(Test_program)
set(CMAKE_CXX_STANDARD 14)
set(GCC_COVERAGE_COMPILE_FLAGS "-DDebug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )
# Contain the header files for testlib
include_directories("C:/test/utils/")
add_subdirectory(lib)
add_executable(Test_program main.cpp)
target_link_libraries(Test_program TEST)
This results in the following output:
-- Linking Test
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/akda/Test_program/cmake-build-debug
[ 33%] Linking C static library libTEST.a
[ 33%] Built target TEST
[ 66%] Building CXX object CMakeFiles/Test_program.dir/main.cpp.obj
[100%] Linking CXX executable Test_program.exe
CMakeFiles\Test_program.dir/objects.a(main.cpp.obj): In function `powerOn()':
C:/Users/akda/Test_program/main.cpp:8: undefined reference to `My_Library_Function'
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe[2]: *** [CMakeFiles\Test_program.dir\build.make:87: Test_program.exe] Error 1
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:77: CMakeFiles/Test_program.dir/all] Error 2
mingw32-make.exe: *** [Makefile:83: all] Error 2
Using tools as DLLExportViewer, I can confirm that the DLL, in fact, does contain the function called.
What am I doing wrong? I'll never claim to be an expert in CMake, but I really can't see what's wrong.
Update with link to .a file
As pointed out, I could try linking with the .a file.
I've added this to the library folder, and changed the main CMakeLists.txt to the following:
cmake_minimum_required(VERSION 3.15)
project(Test_program)
set(CMAKE_CXX_STANDARD 14)
set(GCC_COVERAGE_COMPILE_FLAGS "-DDebug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )
include_directories("C:/test/utils/")
find_library(TEST ${CMAKE_SOURCE_DIR}/lib/libtest.a)
add_executable(Test_program main.cpp)
target_link_libraries(Test_program ${TEST})
And this ends up in the same way, with the same errors.
I am doing FRVT 1:1 verification. So I need to use the program provided by FRVT. I have connected to the program I wrote, and completed implementation.
But I want to transplant what I wrote in cython step by step in the NullImp Example provided by FRVT. But I got this result:
nullimplfrvt11.cpp
....
#include <Python.h> //(is ok)
#include "numpy/arrayobject.h" //(error)
....
CMakelists.txt
cmake_minimum_required(VERSION 2.8)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
include_directories (${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../../../common/src/include)
# Configure built shared libraries in top-level lib directory
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../lib)
find_package(numpy REQUIRED)
find_package(PythonLibs REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
target_link_libraries(${PYTHON_LIBRARIES})
# Build the shared libraries
add_library (frvt_11_null_001 SHARED nullimplfrvt11.cpp)
output:
[root#4d3eca5735a2 11]# bash run_validate_11.sh
Checking installation of required packages [SUCCESS]
Looking for core implementation library in /frvt/11/lib.[SUCCESS] Found core implementation library /frvt/11/lib/libfrvt_11_null_001.so.
Attempting to compile and link /frvt/11/lib/libfrvt_11_null_001.so against test harness.
Scanning dependencies of target validate11
[ 50%] Building CXX object src/testdriver/CMakeFiles/validate11.dir/frvt/common/src/util/util.cpp.o
[100%] Building CXX object src/testdriver/CMakeFiles/validate11.dir/validate11.cpp.o
Linking CXX executable ../../../bin/validate11
../../../lib/libfrvt_11_null_001.so: undefined reference to `PyErr_Format'
../../../lib/libfrvt_11_null_001.so: undefined reference to `PyCObject_AsVoidPtr'
../../../lib/libfrvt_11_null_001.so: undefined reference to `PyExc_RuntimeError'
../../../lib/libfrvt_11_null_001.so: undefined reference to `PyObject_GetAttrString'
../../../lib/libfrvt_11_null_001.so: undefined reference to `PyExc_AttributeError'
../../../lib/libfrvt_11_null_001.so: undefined reference to `PyImport_ImportModule'
../../../lib/libfrvt_11_null_001.so: undefined reference to `PyErr_SetString'
../../../lib/libfrvt_11_null_001.so: undefined reference to `PyCObject_Type'
collect2: error: ld returned 1 exit status
make[2]: *** [../bin/validate11] Error 1
make[1]: *** [src/testdriver/CMakeFiles/validate11.dir/all] Error 2
make: *** [all] Error 2
[ERROR] There were errors during compilation of your library with the validation test harness. Please investigate and re-compile.
There are a few issues with the CMake file. The use of find_package(PythonLibs ...) has been deprecated since CMake 3.12. You should consider using the newer commands, such as find_package(Python2 ...). Also, CMake does not provide a find module specifically for NumPy, you have to specify NumPy as a COMPONENT when you call find_package(Python2 ...). This way, you can use the imported target Python2::NumPy defined by the FindPython module to get the Numpy includes and library.
The call to target_link_libraries() must specify a target to link the libraries to. The only target defined in your CMake file is frvt_11_null_001, so that should be the first argument to target_link_libraries(). You should also prefer to use the target-specific variant of include_directories() so to not pollute the CMake directory scope with include directories.
With these fixes, your CMake can look something like this.
cmake_minimum_required(VERSION 2.8)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# Configure built shared libraries in top-level lib directory
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../lib)
find_package (Python2 COMPONENTS Interpreter NumPy)
# Build the shared libraries
add_library (frvt_11_null_001 SHARED nullimplfrvt11.cpp)
target_include_directories (frvt_11_null_001 PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../include
${CMAKE_CURRENT_SOURCE_DIR}/../../../common/src/include
)
target_link_libraries(frvt_11_null_001 PUBLIC Python2::NumPy)
This is how I did it:
find_package(Python3 3.7 COMPONENTS Interpreter NumPy REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
target_link_libraries(c__14 ${PYTHON_LIBRARIES} Python3::NumPy)
where 3.7 is your version and c__14 is the project name
You can use add_subdirectory() to add numpy library in project.
example add_subdirectory(your/library/path)
As mentioned above i have problems with compiling my c++ project (using CMake) which uses some dynamic libraries (.so).
There are 3 libs in my directory (i.e. home/sources/lib/). When i only tell the compiler (in the CMake file) to use the first lib (foo1.so) it works (only this file, the order does not matter). But it does not work with any of the other libs (foo2.so and foo2.so). All 3 files have the .so extension.
Note: The directory and file names were changed but the structure is the same.
The libraries i am using were not compiled / created by me and are from a 3rd party. (it would not matter when they were broken, would it?)
And this is how my CMake file looks like:
cmake_minimum_required(VERSION 3.3)
project(MyProj)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -m64")
INCLUDE_DIRECTORIES("/home/sources/include")
LINK_DIRECTORIES("/home/sources/lib")
set(SOURCE_FILES main.cpp)
add_executable(MyProj ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(MyProj foo1.so)
Changing the above line to this does not work anymore:
TARGET_LINK_LIBRARIES(MyProj foo1.so foo2.so foo3.so)
Just another way to write it (does not help)
TARGET_LINK_LIBRARIES(MyProj foo1.so)
TARGET_LINK_LIBRARIES(MyProj foo2.so)
TARGET_LINK_LIBRARIES(MyProj foo3.so)
And as mentioned above: ALL 3 libraries are in the SAME directory (which i refer to with LINK_DIRECTORIES)
And this is the error i get when trying to compile with the other libs (as said only foo1.so works):
[ 50%] Linking CXX executable MyProj
/usr/bin/ld: cannot find -lfoo2
/usr/bin/ld: cannot find -lfoo3
collect2: error: ld returned 1 exit status
make[3]: *** [MyProj] Error 1
make[2]: *** [CMakeFiles/MyProj.dir/all] Error 2
make[1]: *** [CMakeFiles/MyProj.dir/rule] Error 2
make: *** [MyProj] Error 2
P.S.: I did some research before posting here but did not find any otherone with this "strange" problem. And for sure i wouldn't have come so far with my CMake file without some googling skills ^^
Not sure, but it seems to me that CMake is looking for libfoo1.so whereas the file is actually foo1.so (the same applies for foo2 and foo3)
Try "importing" the libs:
add_library(foo1 SHARED IMPORTED)
set_property(TARGET foo1 PROPERTY IMPORTED_LOCATION "/home/sources/lib/libfoo1.so")
# same thing for foo2 and foo3 ...
target_link_libraries(MyProj foo1 foo2 foo3)
EDIT
There's also the possibility to provide the full path to the library:
target_link_libraries(MyProj "/home/sources/lib/libfoo1.so"
"/home/sources/lib/libfoo2.so"
"/home/sources/lib/libfoo3.so")
I recently switched the build system of my C++ project to CMake. I am trying to use the ExternalProject_Add function to download the required libraries(there are currently 3 of them, GLM and TINYOBJ are static and GLFW can be either static or dynamic) using git then link to them in my project. I want to be able to link these libraries (and possibly others) with minimal effort so that I can build on multiple platforms. Or if someone else comes in to work on the project, they won't have to worry too much about getting the correct libraries installed.
However, I keep getting these errors when building (on Windows 10 with MinGW):
[100%] Linking CXX executable app\OpenGLTest.exe
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0xd): undefined reference to `FPSCounter::getElapsedTime()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x2b): undefined reference to `FPSCounter::reset()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x54): undefined reference to `FPSCounter::setLastTick()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x5e): undefined reference to `FPSCounter::addFrame()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x12d): undefined reference to `GLCamera::getCameraZoom()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x149): undefined reference to `GLCamera::setCameraZoom(float)'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x1de): undefined reference to `GLCamera::getCameraPosition()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x747): undefined reference to `GLCamera::setCameraTarget(glm::tvec3<float, (glm::precision)0>)'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x771): undefined reference to `GLCamera::setCameraPosition(glm::tvec3<float, (glm::precision)0>)'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x968): undefined reference to `GLRenderer_Deferred::GLRenderer_Deferred()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0xb98): undefined reference to `FPSCounter::FPSCounter()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0xba2): undefined reference to `FPSCounter::FPSCounter()'
collect2.exe: error: ld returned 1 exit status
CMakeFiles\OpenGLTest.dir\build.make:98: recipe for target 'app/OpenGLTest.exe' failed
mingw32-make[2]: *** [app/OpenGLTest.exe] Error 1
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/OpenGLTest.dir/all' failed
mingw32-make[1]: *** [CMakeFiles/OpenGLTest.dir/all] Error 2
Makefile:126: recipe for target 'all' failed
mingw32-make: *** [all] Error 2
My directory structure looks like this:
|-Project
|-BUILD (all the CMake output files are here)
| |-app (this is where the .exe is output to)
| |-downloads (dependencies are downloaded here)
| |-deps
|-OpenGL (this is the source directory)
|-deps-CMakeLists.txt
|-CMakeLists.txt
|-src
|-Main.cpp
|-**Other source files and headers of the "undefined reference" errors are in this directory**
|-RenderSystem
|-More Source files
Here is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(OpenGLTest)
set(CMAKE_CXX_FLAGS "-std=c++11")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/app)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(EX_PROJ_SOURCE_DIR ${CMAKE_BINARY_DIR}/downloads/deps/Source)
set(EX_PROJ_BUILD_DIR ${CMAKE_BINARY_DIR}/downloads/deps/Build)
# Include OpenGL
find_package(OpenGL REQUIRED)
if (OPENGL_FOUND)
include_directories(${OPENGL_INCLUDE_DIR})
endif()
# Include GLEW
find_package(GLEW REQUIRED)
if (GLEW_FOUND)
include_directories(${GLEW_INCLUDE_DIRS})
endif()
set(GLFW_LIB_DIR ${EX_PROJ_BUILD_DIR}/GLFW_EX/src)
link_directories(${GLFW_LIB_DIR})
# Download and unpack gtest at configure time
configure_file(deps-CMakeLists.txt downloads/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/downloads)
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/downloads)
# Add gtest directly to our build
add_subdirectory(${EX_PROJ_SOURCE_DIR}/GLM_EX
${EX_PROJ_BUILD_DIR}/GLM_EX
EXCLUDE_FROM_ALL )
add_subdirectory(${EX_PROJ_SOURCE_DIR}/GLFW_EX
${EX_PROJ_BUILD_DIR}/GLFW_EX
EXCLUDE_FROM_ALL )
add_subdirectory(${EX_PROJ_SOURCE_DIR}/TINYOBJ_EX
${EX_PROJ_BUILD_DIR}/TINYOBJ_EX
EXCLUDE_FROM_ALL )
# Add the gtest include directory, since gtest
# doesn't add that dependency to its gtest target
include_directories(${EX_PROJ_SOURCE_DIR}/GLM_EX/glm
${EX_PROJ_SOURCE_DIR}/GLFW_EX/include
${EX_PROJ_SOURCE_DIR}/TINYOBJ)
# add the executable
add_executable(OpenGLTest src/Main.cpp)
target_link_libraries(OpenGLTest tinyobjloader glm glfw3 ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES})
add_custom_command(TARGET OpenGLTest POST_BUILD # Adds a post-build event to MyTest
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${GLFW_LIB_DIR}/glfw3.dll" # <--this is in-file
$<TARGET_FILE_DIR:OpenGLTest>) # <--this is out-file path
This is the deps-CMakeLists.txt file:
cmake_minimum_required(VERSION 3.2)
project(deps-download LANGUAGES NONE)
include(ExternalProject)
set_directory_properties(PROPERTIES EP_BASE "./deps")
# Include GLFW
ExternalProject_Add (
GLFW_EX
GIT_REPOSITORY "https://github.com/glfw/glfw.git"
GIT_TAG "master"
CMAKE_ARGS -DGLFW_BUILD_EXAMPLES=OFF
-DGLFW_BUILD_TESTS=OFF
-DGLFW_BUILD_DOCS=OFF
-DGLFW_INSTALL=OFF
-DBUILD_SHARED_LIBS=ON
UPDATE_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
# Include GLM
ExternalProject_Add (
GLM_EX
GIT_REPOSITORY "https://github.com/g-truc/glm.git"
GIT_TAG "master"
UPDATE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
# Include TINYOBJ
ExternalProject_Add (
TINYOBJ_EX
GIT_REPOSITORY "https://github.com/syoyo/tinyobjloader.git"
GIT_TAG "master"
UPDATE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
add_dependencies(GLFW_EX GLM_EX TINYOBJ_EX)
My "main" is located in Main.cpp in the "src" directory along with all the files referenced in the errors as "undefined reference". I've added the include directories for all the libraries(right after the ExternalProject_Add command) and attempted to link the dynamic library being built for GLFW but it still doesn't seem to work.
What am I missing to get this to build correctly? Any help would be appreciated.
UPDATE:
I've shuffled some things around and moved the ExternalProject_Add commands to another file which are executed during the configure phase of my build, as suggested by Craig Scott. I've made sure that all the external libraries are linked. I even tested each library separately in a different test project to make sure the CMake files work.
All of the "undefined references" I'm getting are from files that I wrote, and are in my source tree. How/Why are they not being included?
Note: I have also tried to include the "src" directory but doesn't seem to do much of anything.
The main problem I was having was caused by not adding the source files to the final executable. I fixed the issue by adding a file(GLOB... just before the add_executable command like this:
# get all *.cpp files recursively
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
# add the executable
add_executable(OpenGLTest ${SRC_FILES})
I will probably move to a solution that involves a more explicit way of adding source files in the future since GLOBs are not recommended.
Thanks to Craig Scott for your help.
While your CMakeLists.txt file does build the external projects, your OpenGLTest target doesn't link to them. Presumably, they are what provide the missing symbols your linker is complaining about. Simply adding those external projects as dependencies won't also add them to your OpenGLTest target.
To fix this problem, you need to add the external libraries to your target_link_libraries command. Unfortunately, those libraries won't exist when you run CMake (well, not the first time anyway), so you have to manually work out the details of the libraries (but see further below for an alternative). It may be enough to know just the directory in which ExternalProject will put them. It should be predictable for every build, so you can work out what it is by looking at one of your test builds. I believe you can then just add that path to the linker search path and list the base name of the library in the target_link_libraries command (the base name meaning drop any leading "lib" on unix-like platforms as well as the file suffix). If that doesn't work, you will need to construct the full path to the library and add that to the target_link_libraries command instead. This would require more work, especially if you want to build on multiple platforms (the set of CMake variables CMAKE_..._LIBRARY_PREFIX and CMAKE_..._LIBRARY_SUFFIX may be helpful here).
If manually specifying the library details bothers you and if the external projects also use CMake, there is a way to get ExternalProject to download the sources for you but then use add_subdirectory to bring them directly into your project. They would then have CMake targets you could use to specify on your target_link_libraries command and would have the added benefit of always being built with consistent compiler/linker flags as the rest of your project. The technique is discussed with Google Test as the example here:
https://crascit.com/2015/07/25/cmake-gtest/
If you wanted to, you could modify that approach to do the whole build at CMake time and then use find_library or similar, but that would make the CMake step potentially very costly and is not normally recommended.
I'll begin stating that I'm almost complete dumb in Cmake matter.
I have the following CMakeLists.txt for a Kdevelop 4.1 project:
project(uart)
find_package(KDE4 REQUIRED)
include (KDE4Defaults)
include_directories( ${KDE4_INCLUDES} ${QT_INCLUDES} src/include src/include/QSerialDevce )
add_subdirectory(doc)
add_subdirectory(src)
add_subdirectory(icons)
link_directories(/usr/lib)
find_library(SERIALDEVICE_LIB qserialdeviced)
add_executable(uart ${uart_SRCS})
target_link_libraries(uart ${SERIALDEVICE_LIB})
When I try to build my project I see:
uart/build> make -j2
-- Found Qt-Version 4.6.3 (using /usr/bin/qmake-qt4)
-- Found X11: /usr/lib64/libX11.so
-- Found KDE 4.5 include dir: /usr/include/kde4
-- Found KDE 4.5 library dir: /usr/lib64/kde4/devel
-- Found the KDE4 kconfig_compiler4 preprocessor: /usr/bin/kconfig_compiler4
-- Found automoc4: /usr/bin/automoc4
CMake Error at CMakeLists.txt:16 (add_executable):
add_executable called with incorrect number of arguments
CMake Error: Attempt to add link library "/usr/lib/libqserialdeviced.so" to target "uart" which is not built by this project.
-- Configuring incomplete, errors occurred!
make: *** [cmake_check_build_system] Error 1
*** Failed ***
Everything I read says that add_executable and target_link_libraries should look like the last two lines of my file:
add_executable(uart ${uart_SRCS})
target_link_libraries(uart ${SERIALDEVICE_LIB})
If I change those two lines of CMakeLists.txt leaving it as:
project(uart)
find_package(KDE4 REQUIRED)
include (KDE4Defaults)
include_directories( ${KDE4_INCLUDES} ${QT_INCLUDES} src/include src/include/QSerialDevce )
add_subdirectory(doc)
add_subdirectory(src)
add_subdirectory(icons)
link_directories(/usr/lib)
find_library(SERIALDEVICE_LIB qserialdeviced)
target_link_libraries(${SERIALDEVICE_LIB})
I see:
uart/build> make -j2
-- Found Qt-Version 4.6.3 (using /usr/bin/qmake-qt4)
-- Found X11: /usr/lib64/libX11.so
-- Found KDE 4.5 include dir: /usr/include/kde4
-- Found KDE 4.5 library dir: /usr/lib64/kde4/devel
-- Found the KDE4 kconfig_compiler4 preprocessor: /usr/bin/kconfig_compiler4
-- Found automoc4: /usr/bin/automoc4
-- Configuring done
-- Generating done
-- Build files have been written to: uart/build
[ 11%] Built target doc-handbook
[ 11%] Built target uart_automoc
Linking CXX executable uart
CMakeFiles/uart.dir/uart.o: In function `uart::setupSerial()':
uart/src/uart.cpp:126: undefined reference to `AbstractSerial::AbstractSerial(QObject*)'
CMakeFiles/uart.dir/uart.o: In function `uart::setupEnumerator()':
uart/src/uart.cpp:108: undefined reference to `SerialDeviceEnumerator::SerialDeviceEnumerator(QObject*)'
CMakeFiles/uart.dir/uart.o: In function `uart::setupSerial()':
uart_/uart/src/uart.cpp:136: undefined reference to `AbstractSerial::enableEmitStatus(bool)'
CMakeFiles/uart.dir/uart.o: In function `uart::setupEnumerator()':
uart_/uart/src/uart.cpp:112: undefined reference to `SerialDeviceEnumerator::setEnabled(bool)'
collect2: ld returned 1 exit status
make[2]: *** [src/uart] Error 1
make[1]: *** [src/CMakeFiles/uart.dir/all] Error 2
make: *** [all] Error 2
*** Failed ***
That clearly shows that target_link_libraries is not linking my qserialdeviced.
qserialdeviced is at /usr/lib/libqserialdeviced.so.1.0.0, correctly simlinked to /usr/lib/libqserialdeviced.so and easily found if I manually add it in the Makefile.
I obviously tried:
target_link_libraries(-lqserialdeviced)
with no change.
I also tried:
if ("${SERIALDEVICE_LIB}" STREQUAL "SERIALDEVICE_LIB-NOTFOUND")
message(FATAL_ERROR "'qserialdeviced' wasn't found!")
else()
message("'qserialdeviced' found: " ${SERIALDEVICE_LIB})
endif ()
But this test succeeds. The library is found:
'qserialdeviced' found: /usr/lib/libqserialdeviced.so
Can anybody please help me to understand what happens here?
I am using Linux Fedora 13, cmake version 2.8.0, gcc (GCC) 4.4.5 20101112 (Red Hat 4.4.5-2) and kdevelop-4.1.0-1.fc13.x86_64.
Thanks i advance.
EDIT:
As suggested by #DatChu, I split my CMakeLists.txt across my subdirectories and everything makes sense to me now.
Thanks everbody!
For the original CMakeLists.txt file, the problem is not with target_link_libraries but with add_executable
add_executable(uart ${uart_SRCS})
where did you set your uart_SRCS variable? Do you have
set(uart_SRCS src/blahblah.cpp src/somethingblahblah.cpp)
I think you might misunderstand what add_subdirectory does. It does not add the source files inside. It tells CMake to descend into that folder and look for another CMakeLists.txt. You typically use it when you have a sub-project inside of your project folder.
If you have many source files which you don't want to manually set, you can also do
file(GLOB uart_SRCS src/*.cpp src/*.c)
The downside is you need to manually re-run CMake in order for it to detect new files. See Jack's comment on why this might not be what you want to use.
Your CMakeLists.txt will most likely be
project(uart)
find_package(Qt4 REQUIRED)
include (${QT_USE_FILE})
find_package(KDE4 REQUIRED)
include (KDE4Defaults)
include_directories( ${KDE4_INCLUDES} ${QT_INCLUDES} src/include src/include/QSerialDevice )
link_directories(/usr/lib)
file(GLOB uart_SRCS src/*.cpp src/*.h)
file(GLOB uart_HDRS include/*.h include/QSerialDevice/*.h)
find_library(SERIALDEVICE_LIB qserialdeviced)
add_executable(uart ${uart_SRCS} ${uart_HDRS})
target_link_libraries(uart ${SERIALDEVICE_LIB} ${QT_LIBRARIES})
This isn't really a direct solution, but I was having such difficulty with "undefined reference" errors (solved previously by linking the appropriate libraries, but not in this case), until I just discovered something - an incompatibility with c vs cpp somehow. The files that defined these reference functions were in .c files (which would default cmake to compile with a C compiler.) and my file referencing these functions is a .cpp file (using g++ compiler or whatever your environment c++ compiler is). Once I changed the .c file to .cpp the "undefined reference" errors disappeared. Above it looks like your uart file is .cpp, but maybe check what the other files are and try this method. It's probably not the appropriate solution or even one at all, but this might get you through the day and moving forward.