Make all files in a folder accessible to all projects (subdirectories) - c++

I have multiple projects (subdirectories) inside my repository. All projects have only one executable file named main.cpp and they all use libraries from the common folder with #include statements. The folder structure looks like this:
root
|
├────common
| ├──── example.h
| ├──── example.cpp
| ├──── *.h # many header files
| └──── *.cpp # many source files
|
├────Project_A
| ├──── CMakeLists.txt
| └──── main.cpp
|
├────Project_B
| ├──── CMakeLists.txt
| └──── main.cpp
|
└──── CMakeLists.txt
This is my attempt at writing the root's CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project ("root")
file(GLOB_RECURSE CommonLibs ${CMAKE_SOURCE_DIR}/common/*.cpp)
link_libraries(${CommonLibs})
add_subdirectory ("Project_A")
add_subdirectory ("Project_B")
Project_A's CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
add_executable (Project_A "main.cpp")
Project_B's CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
add_executable (Project_B "main.cpp")
However when running any of the projects I get this error:
LNK1107 invalid or corrupt file: cannot read at 0x7AC, file example.h
I don't believe the file is corrupted because before I tried to use link_libraries() in root's CMakeLists.txt I was getting other error:
Unresolved external symbol SomeNamespace::ExampleClass::ExampleClass(bool)
Possible duplicates
Other questions such as this one don't solve my problem because they usually work with a more complex folder structure. Also there are questions that attempt to target only single project like this one, but I have multiple projects.
Can you please provide a concise solution?

Add a CMakeLists.txt to your common/ directory:
root
|
├────common
| ├──── CMakeLists.txt <-------- Add this
| ├──── example.h
....
common/CMakeLists.txt
file(GLOB_RECURSE CommonLibsFiles ${CMAKE_CURRENT_SRC_DIR}/*.cpp)
add_library(CommonLibs ${CommonLibsFiles})
...
root's CMakeLists.txt
...
### NO NEED FOR THESE
file(GLOB_RECURSE CommonLibs ${CMAKE_SOURCE_DIR}/common/*.cpp)
link_libraries(${CommonLibs})
###
add_subdirectory(common) #CommonLibs will now be visible to children directories
...
Now link the libraries as required. For example for project A:
Project_A's CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
add_executable (Project_A "main.cpp")
target_link_libraries(Project_A PRIVATE CommonLibs) #link to common libs here,
All the targets/variables that are created or are visible to parent cmake file, are visible to children. The reverse is not true though. For children to expose their variables to parent, they need to explicitly specify PARENT_SCOPE

The following lines in your top-level CMake do not make much sense:
file(GLOB_RECURSE CommonLibs ${CMAKE_SOURCE_DIR}/common/*.cpp)
link_libraries(${CommonLibs})
The link_libraries() command accepts libraries or library targets, not variables (such as CommonLibs). You can use the CommonLibs variable to define a new library target, then link the library target to your executables using link_libraries():
file(GLOB_RECURSE CommonLibs ${CMAKE_SOURCE_DIR}/common/*.cpp)
# Add this line.
add_library(MyCommonLib SHARED ${CommonLibs})
link_libraries(MyCommonLib)
Please note that the use of link_libraries() in general is discouraged, even in CMake documentation itself. You should prefer linking your MyCommonLib to the specific executables that require it using target_link_libraries.
target_link_libraries(Project_A PRIVATE MyCommonLib)

Related

Link up src/ with CMake as library #include'd with some `libname/` prefix

For my research project I am setting up a project (coom) to benchmark a set of algorithms on a data structure. For unit testing I settled on Bandit, which leaves me with a project structure that looks as follows:
+ root
|-- CMakeLists.txt
|-+ external/
| \-- bandit/
|-+ src/
| |-- CMakeLists.txt
| |-- node.cpp
| \-- node.h
\-+ test/
|-- CMakeLists.txt
|-- test.cpp
\-- test_node.cpp
From my experience with other languages, this seems to me a standard project structure? The test/ folder contains unit tests for the logic in src/ and no dependencies are intermixed with the source and test code, but are instead in external/.
The testing files I want to look as follows (with irrelevant parts removed)
// test/test.cpp
#include <bandit/bandit.h>
(...)
#include "test_node.cpp"
int main(int argc, char* argv[]) {
(...)
}
// test/test_node.cpp
#include <coom/node.h>
(...)
But my problem is, that when I try to compile with cmake .. and the subsequent Makefile, they are unable to find the source code in src/ where I get the compiler error:
fatal error: coom/node.h: No such file or directory.
I would expect the test/CMakeLists.txt should look somewhat like the following:
# test/CMakeLists.txt
add_executable (test_unit test.cpp)
target_link_libraries(test_unit coom)
I cannot figure out how to setup the CMakeLists.txt and src/CMakeLists.txt to ensure I get the desired outcome above. Currently they look as follows:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project (coom VERSION 0.1)
# ============================================================================ #
# Dependencies
(...)
# ============================================================================ #
# COOM project
add_subdirectory (src)
add_subdirectory (test)
# src/CMakeLists.txt
# ============================================================================ #
# Link up files for the library
set(HEADERS
node.h
)
set(SOURCES
node.cpp
)
add_library(coom ${HEADERS} ${SOURCES})
I can see from other projects, that it is possible to link the src/ directory with some libname/ prefix, but I cannot discern from their CMakeLists.txt files what I am doing wrong. I have looked at writing a coom.pc.in file and providing an install-target, and tried to set_target_properties with either FOLDER coom or PREFIX coom, but neither worked. I can hack an include_directory(../src) into the test/CMakeLists.txt to be able to include the file via an #include <node.cpp>, but that screams I'm doing something inherently wrong.
I'm at this point very much pulling my hairs out, and the CMake documentation is of very little help to me.
Your coom target has no include directories defined. You can define the include directories to use for this target (with target_include_directories()), and propagate these include directories so they are visible to the consuming test_unit target (by using PUBLIC):
# src/CMakeLists.txt
# ============================================================================ #
# Link up files for the library
set(HEADERS
node.h
)
set(SOURCES
node.cpp
)
add_library(coom ${HEADERS} ${SOURCES})
target_include_directories(coom PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Furthermore, the file path to the node.h header is coom/src/node.h, not coom/node.h. But, because you now have coom/src as an public include directory, you can use the following to include the node.h header in your test file:
#include <node.h>

Library headers not visible in headers but perfectly visible inside .cpp file under cmake build. Why?

I have a C++ project containing several modules, some built as libraries, with such structure:
/MyProject
+---/build
/ModuleA
+---CMakeLists.txt <- module level CMakeLists
+---/src
| +--CMakeLists.txt <- src level CMakeLists
| +--FileA1.cpp
| +--FileA2.cpp
+---/include
| +--FileA1.h
| +--FileA2.h
| +--FileA3.h
/ModuleB
+---CMakeLists.txt
+---/src
| +--CMakeLists.txt
| +--FileB1.cpp
| +--FileB2.cpp
+---/include
| +--FileB1.h
| +--FileB2.h
| +--FileB3.h
main.cpp
CMakeLists.txt <- project level CMakeLists
CMakeLists.txt files look as follow:
project level:
cmake_minimum_required(VERSION 3.05)
project(MyProject)
subdirs(ModuleA ModuleB)
set(CMAKE_CXX_STANDARD 11)
add_executable(MyProject main.cpp)
target_link_libraries(MyProject ModuleA ModuleB)
module level:
subdirs(src)
src level:
FIND_PACKAGE(SomePackage REQUIRED)
INCLUDE_DIRECTORIES(
${SomePackage_INCLUDE_DIR}
${MyProject_SOURCE_DIR}/ModuleA/include
)
SET(SOURCE_FILES <all files from ModuleA/src goes here>)
ADD_LIBRARY(ModuleA STATIC ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(ModuleA
${SomePackage_LIBRARIES}
)
The problem is: when I include header files from 'SomePackage' in my ModuleA header files (i.e. SomePackageFile.hpp in FileA1.h) I get an error while running a build with make:
fatal error: SomePackageFile.hpp: No such file or directory
When I include them in cpp files they are visible and project compiles correctly. I assume that is sth wrong with CMakeLists on src level or entire hierarchy of files is missing something.
I have a github project to be used as a skeleton for other projects:
https://github.com/gnyiri/cmake-sandbox
If you follow this layout, you will not need to add ${SomePackage_INCLUDE_DIR} to INCLUDE_DIRECTORIES which is not the best way to add directories to the include path otherwise.
In a nutshell, you should define a new library like this:
project(module_a)
set(sources
src/source_a_1.cc
)
add_library(library_a
${sources}
)
target_include_directories(library_a
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
Then, if you define another library (library_b), you only need to add library_a in target_link_libraries:
project(module_b)
# set list of sources, needs to be extended when new source arrives
set(sources
src/source_b_1.cc
)
# define a library (static by default -> liblibrary_b.a or library_a.lib will be generated)
add_library(library_b
${sources}
)
# include directories
target_include_directories(library_b
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
# link library_b
target_link_libraries(library_b
library_a
)
Note that in this source tree, all the header files are located in
<module>/include/<module>
This way you will include a header file from like this:
#include "<module>/<module_header.h>"
This is simply because /include will be on include path.
Switching from INCLUDE_DIRECTORIES() to TARGET_INCLUDE_DIRECTORIES() was the case, no change to the structure of the project was needed.

How debug dynamic library in such situation

Well, I am new to CMake.
I have the following file structure
haze_removal
|---build
|---bin
| |--Test
| |--CMakeLists.txt
|---lib
| |--libtools.so
|---include
| |--tools.hpp
|---test
| |--main.cpp
| |--CMakeLists.txt
|---src
| |--tools.cpp
| |--CMakeLists.txt
|---CMakeLists.txt
The libtools.so is builded from ../src/tools.cpp. I build the whole project in ../build using the following cmake command:
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
The Test is build from ../test/main.cpp
I build this project successfully. But when I debug Test using gdb ./Test, I can't skip in the function that from libtools.so.
These are my CMakeLists.txt from different directories.
CMakeLists.txt under haze_removal/
cmake_minimum_required(VERSION 2.8)
project(haze_removal)
# find needed package
find_package(OpenCV REQUIRED)
# library directory
add_subdirectory(src)
# test
add_subdirectory(test)
CMakeLists.txt under ../src/
# generate dynamic library
# add source file, include directories
aux_source_directory(. TOOLS_SRC)
include_directories(${PROJECT_SOURCE_DIR}/include)
# generate
add_library(tools SHARED ${TOOLS_SRC})
# set output directory and lib's name
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
set_target_properties(tools PROPERTIES OUTPUT_NAME "tools")
# link library
target_link_libraries(tools ${OpenCV_LIBS})
CMakeLists.txt under ../test/
# add source file, include directories, link directories
aux_source_directory(. EXE_SRC)
include_directories(${PROJECT_SOURCE_DIR}/include)
link_directories(${PROJECT_SOURCE_DIR}/lib)
# generate
add_executable(Test ${EXE_SRC})
# set output directory
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# link libraries
target_link_libraries(Test ${OpenCV_LIBS} libtools.so)
My question is how I can debug the functions that from libtools.
Well, I find that why I can't step in the dynamic library even though I set CMAKE_BUILD_TYPE=Debug. Because before I set the build model to Debug I used to set CMAKE_BUILD_TYPE=Release. After I change the build model, I didn't delete the files in the build directory.
I don't know whether the above explanation is right or not, but I do solve my problem.
Thx!

CMakeLists.txt add subfolder which represents namespace (just for organization)

Consider the following setup:
-project
--src
---CMakeLists.txt
---main.cpp
---Application.cpp
---Application.hpp
---subfolder
----SomeClass.cpp
----SomeClass.hpp
--bin
And consider this CMakeLists.txt
project(SampleProject)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
# Include directories
INCLUDE_DIRECTORIES("subfolder")
# Executable
add_executable(${PROJECT_NAME} ${SRC_LIST})
Now, as long as I had all my classes in the same folder (src) everything worked perfectly fine.
But now I want to restructure my application a bit. I want to build a folder-hierarchy that represents the namespaces.
Of course in my includes I would then use
#include "subfolder/SomeClass.hpp"
but it doesn't work that way. I had a look at the manpage but there are so many options in CMake and it's often talking about standalone libraries that have their own CMakeLists.txt... I'm not that far yet. I just want to add a subfolder, that's all.
Until now I've used QMake for my C++ projects, but I wanted to dive into CMake now.
Are there any useful tutorials out there? I've found a few, but they they don't cover the basics.
The recommened way is to use a CMakeLists.txt for every subdirectory in existence. If you want to have subdirectories and organize them without having to create multiple CMakeLists.txt files, you can create one in the main directory with those contents:
project(SampleProject)
cmake_minimum_required(VERSION 2.8)
include_directories(src)
file(GLOB_RECURSE SRC_LIST *.c* *.h*)
# Executable
add_executable(${PROJECT_NAME} ${SRC_LIST})
Using aux_source_directory is used mainly for template related things. Also it's common practice to use a toplevel CMakeLists.txt, which includes the further files, has common project settings etc.:
<project>
|
+- CMakeLists.txt
|
+- src/
|
+-- CMakeLists.txt
|
+-- main.cpp
|
…
So this would look like:
CMakeLists.txt (Project dir):
project(SampleProject)
cmake_minimum_required(VERSION 2.8)
include_directories(src) # Add 'src' to include paths
subdirs(src) # Includes the 'src' directory and its cmake file
# ...
Now you can use the include path as expected.
CMakeLists.txt (src dir):
# Better add src files this way:
add_executable(${PROJECT_NAME} main.cpp Application.cpp)
subdirs(subfolder) # TODO: handle subfolder
The subfolder can be added through an additional library target, that is linked to your executable. Usually there's another CMakeLists.txt file in there.
Also make sure your cmake cache is updated; best you recreate it.

Nested CMake projects multiple definition error when adding header-only library

I have a C++ library organized like:
Library/
CMakeLists.txt
main.cpp
src/
file1.cpp
include/
file1.h
Domains/
CMakeLists.txt
BlackJack/
CMakeLists.txt
src/
foo1.cpp
include/
foo1.h
...
libs/
tapkee/
CMakeLists.txt
include/
foo.hpp
....
Each library(i.e. Domains) contains linking and simple code for organizational purposes:
project(Domains)
cmake_minimum_required(VERSION 2.8)
add_subdirectory(IDomain)
add_subdirectory(Blackjack)
add_library(Domains STATIC)
target_link_libraries(Domains IDomain BLACKJACK)
Each sub-library (i.e. Blackjack) has a really simple CMakeLists.txt that just compiles the library (add_library).
This has been working just fine, until now.
I'm adding a third-party library (http://tapkee.lisitsyn.me/). This is a header-only library. It looks like CMake doesn't support this, but I found some work-arounds. I create a empty dummy.cpp file. Here is the CMakeLists for the third-party library:
project (TAPKEE)
file(GLOB TAPKEE_INCLUDE
"include/tapkee/*.hpp"
"include/tapkee/callbacks/*.hpp"
"include/tapkee/defines/*.hpp"
"include/tapkee/external/*.hpp"
"include/tapkee/neighbors/*.hpp"
"include/tapkee/parameters/*.hpp"
"include/tapkee/routines/*.hpp"
"include/tapkee/traits/*.hpp"
"include/tapkee/utils/*.hpp"
)
add_library(${PROJECT_NAME} header_only_BS.cpp ${TAPKEE_INCLUDE})
Here is the weird thing: My main.cpp and anything in the root src directory can include this tapkee library just fine, but none of the sub-libraries can (i.e. BlackJack). I get thousands of redefinition linker errors for the functions within tapkee.
Here is an example of the top-level CMakeLists:
project(ManifoldLearning)
#Root
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
#Domains
set(BLACKJACK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Domains/Blackjack/include)
set(TAPKEE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/tapkee/include/)
include_directories(${INCLUDE_DIR} ${SRC_DIR})
include_directories(${TAPKEE_INCLUDE_DIR})
include_directories(${BLACKJACK_INCLUDE_DIR})
add_subdirectory(Domains)
#add_subdirectory(libs/tapkee)
add_executable(${PROJECT_NAME} ${SRC_LIST} ${HEADER_LIST})
target_link_libraries(${PROJECT_NAME} Domains)
I've been stuck on this for days, and any help/advice would be appreciated.
Update: I've removed the inclusion of the tapkee CMakeLists.txt (add_subdirectory) as per Antonio's direction. I still get redefinition errors, which I find strange. It's now not compiled anywhere and only included in BlackJack/src/foo1.cpp