Src folder without CMakeLists.txt - cmake

I'm starting with cmake I'm following a tutorial that has as an example the following structure:
$ tree -L 2 ExampleProject/
ExampleProject/
|-- build/
|-- CMakeLists.txt
|-- inc/
| |-- Formula.h
|-- src/
| |-- CMakeLists.txt
| |-- Formula.cpp
| |-- main.cpp
To include the header files that are in the inc folder I just have to include_directories inside CMakeLists.txt in the src folder. However, I would not want to put CMakeLists files in the source folder, because I think that in this folder should be only source files. I don't like to mix build files with application source files. So my idea is to use only top level CMakeLists, ie:
$ tree -L 2 ExampleProject/
ExampleProject/
|-- build/
|-- CMakeLists.txt
|-- inc/
| |-- Formula.h
|-- src/
| |-- Formula.cpp
| |-- main.cpp
That is, I don't want to treat the src folder as a subdirectory.
It is possible? Is there something like source_directories?
Here is how far I managed to get:
cmake_minimum_required(VERSION 3.10)
project(ExampleProject)
set(CMAKE_CXX_STANDARD 14)
include_directories(inc)
set(BINARY ${CMAKE_PROJECT_NAME})
file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h)
set(SOURCES ${SOURCES})
add_executable(${BINARY}_run ${SOURCES})
But it would not work because it has to include the .cpp files.

You can add executable from top level CMakelists.txt file. With add_executable(target src/main.cpp). You can try something like this:
add_executable(output src/main.cpp)
add_library(formula src/Formula.cpp)
target_include_directories(formula PUBLIC inc)
target_link_libraries(output PUBLIC formula)

Related

Is it possible to set output directory of EXPORT_COMPILE_COMMANDS without changing the BINARY_DIR?

CMake generates compile_commands.json in cmake build directory which means that my installation of YouCompleteMe or YCM cannot find it. For YCM to use it I need to move it from the build directory to the source or top level of the project.
Project
|- CMakeLists.txt
|- compile_commands.json (there is what i want)
|- build (this iw where i build my project)
|-- compile_commands.json (this is what i have)
|-- OtherCmakeGenerateStuff
|- src
|-- CMakeLists.txt
|-- main.cc (includes library not in project)
|-lib
|-- CMakeLists.txt
|-- math
|--- CMakeLists.txt
|--- math.cc
|--- math.hh
|-include
|-- globals.hh
|-- definitions.hh
There may be mistakes in these files as I just typed it and haven't tested it. however, my focus is on the top level CMakeLists.txt file.
CMakeLists.txt (Top level)
cmake_minimum_require(VERSION 3.8)
project(just_some_project LANGUAGES CXX VERSION 1.0)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_subdirectory(src)
add_subdirectory(lib)
include_directories(include)
src/CMakeLists.txt
cmake_minimum_require(VERSION 3.8)
project(just_some_project LANGUAGES CXX VERSION 1.0)
find_project(someotherlibrary REQUIRED)
add_executable(main main.cc)
target_include_directories(main PUBLIC math someotherlibraryfound)
lib/CMakeLists.txt (Top level)
cmake_minimum_require(VERSION 3.8)
file(GLOB Headers "*.hh")
file(GLOB Sources "*.cc")
add_library(math STATIC $Sources $Headers)

CMake: avoid building tests by default [duplicate]

I have a small project with cmake. I build a lib and an executable. on the development machine I want also an executable that cannot be build on other machines/environments.
e.g.:
<my-lib>
| -- CMakeLists.txt
|
+ -- src/ -> build the lib/archive
| |-- lib.c
| |-- lib.h
| |-- CMakeLists.txt
|
+ -- tool -> build the tool
| |-- tool.c
| |-- CMakeLists.txt
|
+ -- tests -> build the unit tests
| |-- tests.c
| |-- CMakeLists.txt
I added CMakeLists.txt to all directories. Also an add_executable to the tests. Now the unit-test executable is build by default. But I want to exclude it from default target.
CMakeLists.txt in tests:
find_library (CUNIT_LIB cunit)
include_directories (${Cunit_INCLUDE_DIRS} "${PROJECT_SOURCE_DIR}/src")
set (CMAKE_C_FLAGS "-O2 -Wall -Werror")
add_executable (unit-test tests.c)
target_link_libraries (unit-test my-lib cunit)
Has anyone a hint how to handle this? I don't want to build unit-test always!
There is a property EXCLUDE_FROM_ALL for such task.
You can write:
set_target_properties(unit-test PROPERTIES EXCLUDE_FROM_ALL TRUE)
This is very simple: protect creation of executable by introducing an option/variable.
if (DEFINED WITH_UNIT_TEST)
find_library (CUNIT_LIB cunit)
include_directories (${Cunit_INCLUDE_DIRS} "${PROJECT_SOURCE_DIR}/src")
set (CMAKE_C_FLAGS "-O2 -Wall -Werror")
add_executable (unit-test tests.c)
target_link_libraries (unit-test my-lib cunit)
endif ()
Now when invoking CMake, one would have to explicitly specify -DWITH_UNIT_TEST, so that unit-test target is built, while by default it will never be build. For alternative approach, see comments.

Multiple sub-projects depending on the same library

I have a project main_project. It depends on two libraries - libA and libB, which in turn depend on lib_common each.
Graphically project's structure looks like this:
main_project
|
+-libA
| |
| +-CMakeLists.txt
|
+-libB
| |
| +-CMakeLists.txt
|
+-lib_common
| |
| +-CMakeLists.txt
|
+-CMakeLists.txt
Since libA uses lib_common it's pretty natural to call add_subdirectory(lib_common) inside libA's CMakeLists.txt. But the libB also depends on lib_common. If I put it in a subdirectory again it will compile twice. And I don't want that. Also I want to keep all my subprojects clean and self-contained - that's why I don't want to put lib_common in top-level main_project's CMakeLists.txt (because lib_common have nothing with main_project).
Which options do I have?
I would add one more abstraction level to your project structure:
app - this is for executables and for everything that belongs to them,
lib - libraries for the application.
The top-level CMakeLists.txt will only know that there is two different thing, the app sub-project and the lib sub-project. An example directory structure could look like follows:
FooProject
|-- app
|   |-- CMakeLists.txt
|   `-- src
|   `-- foo.cpp
|-- CMakeLists.txt
`-- lib
|-- CMakeLists.txt
|-- libA
|   |-- CMakeLists.txt
|   |-- inc
|   |   `-- bar.h
|   `-- src
|   `-- bar.cpp
|-- libB
|   |-- CMakeLists.txt
|   |-- inc
|   |   `-- baz.h
|   `-- src
|   `-- baz.cpp
`-- lib_common
|-- CMakeLists.txt
|-- inc
|   `-- common_tool.h
`-- src
`-- common_tool.cpp
The top-level CMakeLists.txt contains only the following:
cmake_minimum_required(VERSION 2.8)
project(FooProject)
add_subdirectory(lib)
add_subdirectory(app)
The app/CMakeLists.txt should know that there is a lib folder from where you can include headers and that the executable depends on the libA and the libB:
project(foo)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../lib)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src FOO_SOURCES)
add_executable(foo ${FOO_SOURCES})
add_dependencies(foo libA libB)
target_link_libraries(foo libA libB)
install(TARGETS foo RUNTIME DESTINATION bin ARCHIVE DESTINATION bin)
The lib/CMakeLists.txt exists to tie together the libA, libB and lib_common:
cmake_minimum_required(VERSION 2.8)
add_subdirectory(lib_common)
add_subdirectory(libA)
add_subdirectory(libB)
Let's say that lib_common has no dependencies, so the lib/lib_common/CMakeLists.txt won't see outside of its folder:
project(lib_common)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src LIBCOMMON_SOURCES)
add_library(lib_common ${LIBCOMMON_SOURCES})
In this example the lib/libA/CMakeLists.txt and lib/libB/CMakeLists.txt have almost identical content and only they deal with the lib_common:
project(libA)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc ${CMAKE_CURRENT_SOURCE_DIR}/..)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src LIBA_SOURCES)
add_library(libA ${LIBA_SOURCES})
add_dependencies(libA lib_common)
target_link_libraries(libA lib_common)
install(TARGETS libA LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
In this example the lib sub-project is what you can call as clean and self-contained.
I think this a fairly standard CMake solution:
# toplevel CMakeLists.txt
add_subdirectory(libA)
add_subdirectory(libB)
add_subdirectory(lib_common)
# libA CmakeLists.txt
add_library(libA ${LIBA_SOURCES})
target_link_libraries(libA lib_common)
and similar for libB.
You do not have to call add_subdirectory(lib_common) before add_subdirectory(libA), CMake handles the dependency management automatically.

How to configure cmake to get an executable not by default

I have a small project with cmake. I build a lib and an executable. on the development machine I want also an executable that cannot be build on other machines/environments.
e.g.:
<my-lib>
| -- CMakeLists.txt
|
+ -- src/ -> build the lib/archive
| |-- lib.c
| |-- lib.h
| |-- CMakeLists.txt
|
+ -- tool -> build the tool
| |-- tool.c
| |-- CMakeLists.txt
|
+ -- tests -> build the unit tests
| |-- tests.c
| |-- CMakeLists.txt
I added CMakeLists.txt to all directories. Also an add_executable to the tests. Now the unit-test executable is build by default. But I want to exclude it from default target.
CMakeLists.txt in tests:
find_library (CUNIT_LIB cunit)
include_directories (${Cunit_INCLUDE_DIRS} "${PROJECT_SOURCE_DIR}/src")
set (CMAKE_C_FLAGS "-O2 -Wall -Werror")
add_executable (unit-test tests.c)
target_link_libraries (unit-test my-lib cunit)
Has anyone a hint how to handle this? I don't want to build unit-test always!
There is a property EXCLUDE_FROM_ALL for such task.
You can write:
set_target_properties(unit-test PROPERTIES EXCLUDE_FROM_ALL TRUE)
This is very simple: protect creation of executable by introducing an option/variable.
if (DEFINED WITH_UNIT_TEST)
find_library (CUNIT_LIB cunit)
include_directories (${Cunit_INCLUDE_DIRS} "${PROJECT_SOURCE_DIR}/src")
set (CMAKE_C_FLAGS "-O2 -Wall -Werror")
add_executable (unit-test tests.c)
target_link_libraries (unit-test my-lib cunit)
endif ()
Now when invoking CMake, one would have to explicitly specify -DWITH_UNIT_TEST, so that unit-test target is built, while by default it will never be build. For alternative approach, see comments.

UnitTest++ and g++ - Relative path to the library

I'm trying to get UnitTest++ to work in a project following this directory tree:
Project/
|-- src/
|-- test/
| |-- test.cpp
|-- unittest-cpp/
| |-- UnitTest++/
| |-- libUnitTest++.a
| |-- src/
| |-- UnitTest++.h
|-- Makefile
I'm trying to compile with g++ while in the Project directory. My test.cpp file contains the UnitTest++ Getting Started code.
I tried the following:
g++ -Lunittest-cpp/UnitTest++/ -lUnitTest++ -Iunittest-cpp/UnitTest++/src/ \
test/test.cpp -o Test
If I understand well, -L is to give the path to the static library. -l (Small L) is for the library name and -I (Capital i) is for the include path.
I get two different results. It either tells me it cannot find the lib in /usr/bin/??? or it tells me that there are undefined references to unittest::*.
Is it because I'm giving a relative path to the library that it cannot compile? I'm new to using g++ through multiple directories and I'm trying to understand how it works before getting it to work in my Makefile.
[EDIT]: The test/test.cpp parameter had to be given before linking the libraries and headers. So, this worked:
g++ test/test.cpp -Lunittest-cpp/UnitTest++ -lUnitTest++ -Iunittest-cpp/UnitTest++/src -o Test
The file to compile (in this context test.cpp) has to be given before its dependancies when compiling. This worked:
g++ test/test.cpp -Lunittest-cpp/UnitTest++ -lUnitTest++ -Iunittest-cpp/UnitTest++/src -o Test
If you are using this project structure, you can use Cmake that helps to link all the libraries to the target.
target_link_libraries(Target_name All_the_libraries_you_want_to_link)