CMake generate demo executable for library project - cmake

I am currently writing a library and want to add a demo executable to show how to use the library. The problem I am facing now, is that I cant use find_package inside the demos CMakeLists.txt because the library has not been installed yet during the generation phase.
The structure of the project looks as follows:
- lib/
-- CMakeLists.txt
-- lib.hpp
-- lib.cpp
- demo/
-- CMakeLists.txt
-- demo.cpp
- CMakeLists.txt
In the root CMakeLists.txt I use add_subdirectory(lib) and after that add_subdirectory(demo) but only if the LIB_BUILD_DEMO flag is set.
In the demo/CmakeLists.txt I use find_package(lib REQUIRED) and then link my executable against that library.
Now I get errors that the lib-config.cmake file could not be found which makes sense because cmake --install . has not been called yet.
How can I build the demo that uses the library?

Related

How to include a library using CMAKE in a cross-platform way

I am trying to use the assimp library in a cross platform C++ project. I include the repo as a git submodule, so, effectively, if someone downloads my project they will also download the ASSIMP project.
After I go through the assimp build / CMAKE instructions and (on Linux) type make install and from then on in my project I can use:
target_link_libraries(${PROJECT_NAME} assimp)
However, there is no make install on Windows.
The only other way I have been able to include the library on Linux is to put (in my CmakeLists.txt file):
target_link_libraries(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/build/assimp/code/libassimp.so)
This is not cross platform as it hardcodes the name and location of the .so file which will not work on Windows.
How can I expose the library so that I can do something like target_link_libraries(${PROJECT_NAME} assimp) on all platforms?
My directory tree looks like:
- src
- include
- assimp
- bin
Where the assimp directory in the include directory is the git submodule
I think you're going about this the wrong way. You don't need to build assimp in a separate step from your project, and you don't need to make install to make it available.
There are a number of ways of handling third party dependencies in Cmake, since you've already chosen to submodule the assimp repository, we'll start there. Assuming assimp is located in the root of your repository in a directory called assimp/ this would be a barebones project including it:
cmake_minimum_required(VERSION 3.0)
project(Project myassimpproj)
# include your directories
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
# set any variables you might need to set for your app and assimp
set(BUILD_ASSIMP_TOOLS ON)
set(ASSIMP_BUILD_STATIC_LIB ON)
# add assimp source dir as a subdirectory, effectively making
# assimp's CMakeLists.txt part of your build
add_subdirectory(/path/to/assimp ${CMAKE_BINARY_DIR}/assimp)
add_executable(assimp_target main.cpp)
# be sure to link in assimp, use platform-agnostic syntax for the linker
target_link_libraries(assimp_target assimp)
There may be a better way of phrasing this using generator expressions syntax, but I haven't looked at assimp's CMakeLists.txt to know if it's supported (and this is a more generic way anyway.)
Not every project uses Cmake, so you may not be able to just add_subdirectory(). In those cases, you can effectively "fake" a user call to build them using their build commands on respective platforms. execute_process() runs a command at configure time add_custom_command() and add_custom_target() run commands at build time. You then create a fake target to make integration and cross your fingers they support Cmake someday.
You can also use the ExternalProject commands added to Cmake to create a custom target to drive download, update/patch, configure, build, install and test steps of an external project, but note that this solution and the next download the dependency rather than using the submodule'd source code.
Finally, I prefer to work with prebuilt dependencies, cuts down on build time, and they can be unit tested on their own outside of the project. Conan is an open source, decentralized and multi-platform package manager with very good support for C++ and almost transparent support for Cmake when used the right way. They have grown very stable in the last year. More information on how to use Conan with Cmake can be found here.

CMake execution order - first build shared library then look for it from another project

I have the following cmake setup:
colorizer_root
|
|-------colorizer_lib
|-------colorizer_template_project
The colorizer_root contains the top level CMakeLists.txt which is invoked when running cmake:
colorizer_root CMakeLists.txt
project(colorizer_root)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE Debug)
add_subdirectory(colorizer_lib)
add_subdirectory(colorizer_template_project)
As you can see it contains 2 subdirectories each a project on its own. Basically what the colorizer_lib does is create a shared library named libcolorize.so (no executables here!), which then is to be used by the other project colorizer_template_project (the executable is created in this project). Here are the two CMakeLists.txt files for their respective projects:
colorizer_lib CMakeLists.txt
project(colorizer_lib)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_CXX_FLAGS "--std=gnu++11 ${CMAKE_CXX_FLAGS}")
include_directories(. INCLUDES)
add_library(colorizer SHARED colorizer.cpp)
colorizer_template_project CMakeLists.txt
project(colorizer_template_project)
cmake_minimum_required(VERSION 2.8)
find_library(COLORIZER_LIB colorizer
PATHS ${CMAKE_BINARY_DIR}/colorizer_lib
)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} ${COLORIZER_LIB})
I'm having trouble figuring out how the whole lookup thing works. The problem here is that when I run the top level CMakeLists.txt it goes through both (obviously) but during processing the colorizer_template_project it breaks with a complaint:
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
COLORIZER_LIB
linked by target "colorizer_template_project" in directory /home/USER/Programming/C_Cpp/colorizer/colorizer_template_project
This is an expected behaviour since libcolorizer.so cannot be present at the time of running cmake because it is created after make has been invoked.
How do I tell cmake to first process the first project (including the build step!) and then go to the next one? I know that this works if I add an executable to the project that creates the library and then directly link it to the binary but in this case I want separate projects for the library and the executable that is using it.
PS: I haven't given any details about the sources because they are not important here. It is - I believe - a general question, which is not specific to whether I'm using C, C++ or something similar.
project command doesn't make subprojects independent, so colorizer target is actually accessible for colorizer_template_project, and you can directly link with it:
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} colorizer)

cmake - Link custom library from higher level directory

I'm learning about cmake and am finding it very fast to learn. However, documentation is not up to scratch. The tutorials are helpful, but only go so far.
What I have is an existing project that I want to convert to using cmake.
The project structure currently looks like:
obsys/
obsys/client/ {client files}
obsys/server/ {server files}
obsys/utils/include
obsys/utils/src
I've created CMakeLists.txt files at each level.
The top level looks currently like this:
make_minimum_required (VERSION 2.6)
project (osys)
add_subdirectory (server)
add_subdirectory (utils)
Inside utils I have a CMakeLists.txt that contains:
include_directories ("${PROJECT_SOURCE_DIR}/utils/include")
add_subdirectory (src)
and inside the utils src directory the CMakeLists.txt file contains:
add_library(utils myException.cpp)
The server needs to link to utils. It's CMakeLists.txt contains:
make_minimum_required (VERSION 2.6)
project (server)
include_directories ("../utils/include")
add_executable(serv serv.cpp)
add_subdirectory("../utils/src" utils)
target_link_libraries(obbsd utils)
The idea with this layout is I was hoping I could build the whole lot through the top level Makefile. Or, jump into server, or client and build either of them. It's not working out that way. What is the recommended way to do this?
Ok, I now have it working.
The problem is that my add_executable line wasn't listing all the source files.
Link seemed to be complaining about something to do with utils which made me think it wasn't finding the library when actually it was.

CMake add_subdirectory()

Introduction:
I am trying to use CMake to obtain cross platform compilation scripts (for VS 9.0 on a Windows32 and Makefiles for Unix).
I am experiencing something i can't understand about add_subdirectory().
Let me show you my code :
Context:
My architecture for a module named "module1" is something like this :
CMakeLists.txt
include/
file1.h
file2.h
*.h
src/
file1.cpp
file2.cpp
*.cpp
test/
CMakeLists.txt
src/
testfile1.cpp
testfile2.cpp
The architecture of my whole application is composed of these modules which are in themselves projects that could work independantly.
My goals:
I want to compile my module as a library
I want to test the library with the code in the test/ folder
Here are the CMakeLists i wrote :
This one is the CMakeLists.txt in the root directory of my module.
#ENSURE MINIMUM VERSION OF CMAKE
cmake_minimum_required(VERSION 2.8)
#CONFIGURATION OF THE PROJECT
#NAME OF THE PROJECT
project(MyProject)
#OUTPUT OF THE PROJECT
set(LIBRARY_OUTPUT_PATH lib/${CMAKE_BUILD_TYPE})
#ADD THE HEADERS OF THE LIBRARY BEING CREATED
include_directories(include)
#ADD 3rd PARTY OPENCV LIBRARIES
find_package(OpenCV REQUIRED)
#ADD 3rd PARTY XERCES LIBRARIES
include_directories(${XERCES_INCLUDE_DIR})
link_directories(${XERCES_LIB_DIR})
set(Xerces_LIBS xerces-c_3D.lib)
#CONFIGURATION OF THE LIBRARY
file(GLOB_RECURSE MYPROJECT_MODULE_CXX src/*)
file(GLOB_RECURSE MYPROJECT_MODULE_HDR include/*)
#NAME OF THE PRESENT LIBRARY
set(MYPROJECT_MODULE_LIB_NAME myModuleLib)
add_library(${MYPROJECT_MODULE_LIB_NAME}
SHARED
${MYPROJECT_MODULE_CXX}
${MYPROJECT_MODULE_HDR}
)
target_link_libraries(${MYPROJECT_MODULE_LIB_NAME}
${OpenCV_LIBS}
${Xerces_LIBS}
)
#CONTINUE IN THE SUB FOLDERS
add_subdirectory(test)
And then, in the test/ folder, here is the CMakeLists.txt
#ENSURE MINIMUM VERSION OF CMAKE
cmake_minimum_required(VERSION 2.8)
#CONFIGURATION OF THE PROJECT
#NAME OF THE PROJECT
project(MyProjectTest)
#OUTPUT OF THE PROJECT
set(EXECUTABLE_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE})
#ADD OUR TESTED LIBRARY
include_directories(../include)
link_directories(../build/lib/${CMAKE_BUILD_TYPE})
#CONFIGURATION OF THE EXE
file(GLOB_RECURSE MYPROJECT_MODULE_TEST_CXX src/*)
#NAME OF THE PRESENT EXECUTABLE
set(MYPROJECT_MODULE_TEST_BIN_NAME myModuleTest)
add_executable(${MYPROJECT_MODULE_TEST_BIN_NAME}
${MYPROJECT_MODULE_TEST_CXX}
)
target_link_libraries(${MYPROJECT_MODULE_TEST_BIN_NAME}
${MYPROJECT_MODULE_LIB_NAME}
)
Question
The CMake outputs a correct MyProject.sln Visual Studio 9.0 solution, which compiles successfully in my library linked with OpenCV and Xerces (and other 3rd part libraries). However the test binary did not output any MyProjectTest.sln.
I thought, (and read in the CMake documentation) that add_subdirectory(dir) was used to do CMake in the following sub directory (i mean, the name could not be clearer :p !), so shouldn't it continue CMake in the test/ directory and create my MyProjectTest.sln solution ?
I use the GUI CMake to run the root CMakeLists.txt in a build directory that i create in the root of my module. When I explore the build directory that's where I can find my MyProjet.sln, a test/ folder, but no MyProjectTest.sln in it !
This may not solve your original problem but in your test/folder/CMakeLists.txt try changing
#ADD OUR TESTED LIBRARY
include_directories(../include)
link_directories(../build/lib/${CMAKE_BUILD_TYPE})
to
#ADD OUR TESTED LIBRARY
include_directories(${CMAKE_SOURCE_DIR}/include)
link_directories(${CMAKE_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE})
otherwise you are assuming that your build folder is always named build.
After three days trying everything, I finally found the answer... Sir DLRdave was right actually: the problem was not from the code itself but from something "out of the code".
Problem found:
I created and edited all my files with Notepad++. Actually when opening the files with windows notepad (because i was curious) a strange rectangle symbol appeared and the file did not look like the one I usually see on Notepad++
I found out that the symbol was a "\n\r" that Notepad++ did not show me (it must be filtered) but going on windows notepad, you could see that the whole file was "impure" and appeared on a single line instead of the layout i saw on Notepad++.
As this "encoding" bug appeared only in the subdirectory CMakeLists, it could not be read but said no error when interpreting with CMake and that's probably why I had no returned error from running CMake.
Solution:
I used the native2ascii.exe tool from Java to correct the encoding error.
The why:
Actually what it probably means is that the syntaxic parser of CMake has probably not been designed for filtering this type of char appearing with strange encoding, that's why it gave me 3 days of intense debugging.

Building tests with CMake while not using CTest

Here is what I want to do:
Typing make all will build my library and the docs for it.
Typing make test will build my lib (if necessary), gtest and then my tests
Typing make check runs make test if needed and then runs the executable
Right now I've only managed to get the first to work.
The problem I'm having is the conditional include of gtest.
Gtest uses CMake which is nice, in theory all I need to do is to include the gtest directory with add_subdirectory but then gtest will always be built.
My structure right now is:
CMakeLists.txt (Here I add targets for doc and the library)
doc (my doxygen docs)
include (my headers)
lib (where my compiled libraries go)
src (where my .cpp files go)
test
CMakeLists.txt (Here I add targets for gest and my tests)
bin (where the test executable will go)
contrib (where gtest is)
src (my tests)
I'm trying to figure out how to add gtest as a dependency to the test-target but not build gtest every time.
I'm really annoyed and the little to none information there is about learning CMake so if anyone know any in depth tutorials (available freely on the interwebs) that would be awesome.
The trick is to do add_subdirectory(test EXCLUDE_FROM_ALL) and then none of the targets in that CMakeList.txt will added to the ALL target.