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

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)

Related

Using Taglib in CMake project without installing it

I am making a CMake project and the objective is to produce an executable, on either Windows or Unix (but not macOS), by statically linking or by directly using the source code of the third party library (Which is Taglib). I am looking into doing something as simple as that.
git clone --recurse-submodules https://github.com/MyGitAccount/MyProject.git
cd MyProject
cmake .
make
Here's are some details about my CMake project:
My project repository has a reference as a submodule to the Taglib repository.
Consider that Git, CMake and the compiler toolchain (build-essential or MinGW) are installed by default.
Project Tree Structure
ProjectName/
|-- Preload.cmake
|-- CMakeLists.txt
|-- src/
|-- CMakeLists.txt
|-- main.cpp
|-- taglib/
|-- CMakeLists.txt
|-- taglib/ (This folder is a submodule to my repository. It repository can be found here:
https://github.com/taglib/taglib)
|-- CMakeLists.txt
|-- ConfigureChecks.cmake
|-- cmake_uninstall.cmake.in
|-- config.h.cmake
|-- taglib-config.cmake
|-- taglib-config.cmd.cmake
|-- taglib.pc.cmake
|-- cmake/
|-- modules/
|-- FindCppUnit.cmake/
|-- MacroEnsureVersion.cmake/
ProjectName/Preload.cmake
if(UNIX AND NOT APPLE)
set (CMAKE_GENERATOR "Unix Makefiles" CACHE INTERNAL "" FORCE)
endif()
if(WIN32)
set (CMAKE_GENERATOR "MinGW Makefiles" CACHE INTERNAL "" FORCE)
endif()
ProjectName/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(ProjectName)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_subdirectory(taglib)
# add_subdirectory(src) # In comment for debugging purpose
ProjectName/taglib/CMakeLists.txt
set(taglib_DIR ./taglib)
find_package(taglib CONFIG)
if (Taglib_FOUND)
message("Found!")
else()
message("Not Found...")
endif()
ProjectName/src/CMakeLists.txt
file(GLOB sources "*.c" "*.cpp")
file(GLOB headers "*.h" "*.hpp")
add_executable(${CMAKE_PROJECT_NAME} ${sources} ${headers})
target_include_directories(${CMAKE_PROJECT_NAME} ${Taglib_INCLUDE_DIRS})
target_link_libraries(${CMAKE_PROJECT_NAME} ${Taglib_LIBRARIES})
Then, when running "cmake ." in "MyProject/", I obtain this error (On Windows 10).
C:\Users\UserName\Desktop\MyProject>cmake .
-- The C compiler identification is GNU 9.2.0
-- The CXX compiler identification is GNU 9.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/MinGW/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/MinGW/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Error at taglib/taglib/taglib-config.cmake:4:
Parse error. Expected a command name, got unquoted argument with text "{".
Call Stack (most recent call first):
taglib/CMakeLists.txt:5 (find_package)
CMake Error at taglib/CMakeLists.txt:5 (find_package):
find_package Error reading CMake code from
"C:/Users/UserName/Desktop/MyProject/taglib/./taglib/taglib-config.cmake".
-- Configuring incomplete, errors occurred!
See also "C:/Users/UserName/Desktop/MyProject/CMakeFiles/CMakeOutput.log".
I also tried to use one of the "FindTaglib.cmake" files that I have found while googling.
I have successively placed those files in "MyProject/cmake/modules/ and set the variable "CMAKE_MODULE_PATH" but it wasn't successful.

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.

Src folder without CMakeLists.txt

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)

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.