Cmake with multiple directories - c++

project
|------ CMakeLists.txt (The main Cmake)
|------ somePlace/someOtherPlace/CmakeLists.txt
| |----- some.proto (google proto files)
| |----- CMakeList.txt
|------ Project2/CmakeListst.txt
|----- .cpp files
|----- .hpp files
|----- CMakeList.txt
I have a similar topology as above, my main cmake could be able to generate cmake files, and after the main cmake I could be able to build Project2 with:
make Project2
I have added Project2 as subdirectory to the main cmake. I have no problem here. But I also want to build common/someplace/CmakeLists.txt together with the Project2, when I run make Project2. I also know that I could be able to build common/someplace/CmakeLists.txt inside its directory by cmake and make commands. You can check somePlace/someOtherPlace/CmakeLists.txt :
INCLUDE(FindProtobuf)
FIND_PACKAGE(Protobuf REQUIRED)
INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER oamc_packets.proto)
ADD_LIBRARY(proto ${PROTO_HEADER} ${PROTO_SRC})
But I want Project2 to depend on somePlace/someOtherPlace/CmakeList.txt and build together with it.How can I achieve it?
Should I use add_executable/add_library commands? The problem is somePlace/someOtherPlace/CmakeLists.txt creates header and cc file along with the .a file.
PS: I can give further information, if it is requested.

I peeked into the documentation of FindProtobuf, and they put a warning here
Note: The protobuf_generate_cpp and protobuf_generate_python functions and add_executable() or add_library() calls only work properly within the same directory.
So perhaps if you could include the content of somePlace/someOtherPlace/CmakeList.txt inside your Project2/CmakeListst.txt, then you could safely use the generated file.
I can't really test the following code, but maybe in Project2/CmakeListst.txt before using the generated files you can do
include("${CMAKE_CURRENT_SOURCE_DIR}/../somePlace/someOtherPlace/CmakeLists.txt")

Related

Cmake adding a source folder to xcode without compiling the sources inside

I have a project that I am porting to cmake. The architecture of the sources is as follow:
src
|- FolderA
|-fileAa.cpp
|-fileAb.cpp
...
|- fileA.cpp
|-CMakeLists.txt
...
The file fileA.cpp is as follow:
#include <FolderA/fileAa.cpp>
#include <FolderA/fileAb.cpp>
//etc
My CMakeFiles.txt is as follow (the files from FolderA ARE NOT included in the add_library function)
#...
add_library(... fileA.cpp ...)
#...
And it works well. When I tried to build the library, if I modify any files inside FolderA, only the file fileA.cpp is rebuilt and the library is remade.
However, when I generate my project for Xcode, the files inside FolderA are not shown. Is there a way to tell cmake that I want it to include the files inside FolderA in my Xcode project (and any other supported IDE) but without adding them to the list of files to compile for the add_library function?
I tried to set the property of the files in FolderA as HEADER and still include them in add_library (as mentioned here) and it sort of worked, but in Xcode the files were displayed in a flat hierarchy and I would like to keep the same structure:
What I want in Xcode:
|-FolderA
|-fileAa.cpp
|-fileAb.cpp
...
|- fileA.cpp
What I have in Xcode:
|-fileAa.cpp
|-fileAb.cpp
|-fileA.cpp
...
I there a way to tell cmake to include a folder and its content to the project generated for an IDE, without adding the files I want to the list of files to compile ?
I solved my problem.
As mentioned here I need to use the files in a target for source_group to work. I used the trick that I mentionned of setting the sources of FolderA as header files and it worked perfectly:
file(GLOB COMPILED_SOURCES "*.cpp")
file(GLOB FOLDERA_SOURCES "FolderA/*.cpp")
set_source_files_properties(${FOLDERA_SOURCES} PROPERTIES HEADER_FILES_ONLY TRUE)
source_group(TREE ${PROJECT_SOURCE_DIR}/src FILES ${COMPILED_SOURCES} ${FOLDERA_SOURCES})
#...
<any function that create a target>(... ${COMPILED_SOURCES} ${FOLDERA_SOURCES} ... )
#...

Project Linking and Compiling files

I want to start building a project and I have the following folder structure:
lib
|---class1.cpp
|---class1.hpp
src
|---main.cpp
I have the MinGW compiler and I don't know how to compile all .cpp files. I know the command g++ *.cpp -o main for compiling all the files, but works only for files in the same folder.
Should I move all my files to the src folder? Should I change the project structure?
Also, I'm really doubtful if I should use CMake or not.
FINAL:
I decided to go with CMake which made my life easier.
For a barebones project, your structure is fine. Just add the following CMakeLists.txt file to the root of your directory:
cmake_minimum_required(VERSION 3.5)
# Given your project a descriptive name
project(cool_project)
# CHoose whatever standard you want here... 11, 14, 17, ...
set(CMAKE_CXX_STANDARD 14)
# The first entry is the name of the target (a.k.a. the executable that will be built)
# every entry after that should be the path to the cpp files that need to be built
add_executable(cool_exe src/main.cpp lib/class1.cpp)
# Tell the compiler where the header files are
target_link_libraries(cool_exe PRIVATE lib)
Your directory should now look like
CMakeLists.txt
lib
|---class1.cpp
|---class1.hpp
src
|---main.cpp
Then to build the project, you will typically
Make a folder where you build everything (often called build, but it's up to you). Now the directory looks like
CMakeLists.txt
lib
|---class1.cpp
|---class1.hpp
src
|---main.cpp
build
Go into the build folder and on the command like, configure your project with the command cmake .. (just to reiterate... this needs to be done from inside the build folder).
Build your project with the make command (again from inside the build folder).
After that, you should have an executable called cool_exe in the build folder.

CMake target_include_directories does not affect header files

My project is roughly structured like this:
├CMakeLists.txt
|
├───ExampleApp
| ├───CMakeLists.txt
| ├───header.hpp
| └───main.cpp
|
└───ExampleLibrary
├───CMakeLists.txt
├───mylib.hpp
└───mylib.cpp
In the root CMakeLists.txt I call
add_subdirectory(ExampleLibrary)
add_subdirectory(ExampleApp)
To build the library I call:
add_library(ExampleLibrary
mylib.hpp mylib.cpp
)
And finally, in the executable, I try to do:
add_executable(ExampleApp
header.hpp main.cpp
)
target_include_directories(ExampleApp
PRIVATE ${PROJECT_SOURCE_DIR}/ExampleLibrary
)
target_link_libraries(ExampleApp
Path/To/The/Binary/Directory
)
Now the build files generate just fine, and the project also builds with no errors. However, when I now try to include mylib.hpp in header.hpp, I get build errors because it can't find the file mylib.hpp. But I actually can include mylib.hpp in main.cpp and the project builds and compiles.
Am I missing something? I thought target_include_directories() works for both .cpp and .hpp files.
It seems like you may not have added the correct directory as an include directory for the ExampleApp. The PROJECT_SOURCE_DIR variable evaluates to the directory in which the last project() call was made in your CMake project. You have not shown where this is, but you could use the root directory of the CMake project to be sure it is correct; try using ${CMAKE_SOURCE_DIR}/ExampleLibrary in the target_include_directories call instead:
target_include_directories(ExampleApp
PRIVATE ${CMAKE_SOURCE_DIR}/ExampleLibrary
)
A couple more notes:
If you aren't using an IDE such as Visual Studio for compilation, there is no need to add header files to calls like add_library() and add_executable(). Doing this only ensures they are shown in an IDE.
Instead, specify directories within which the headers can be found, using target_include_directories(). In your case, it sounds like you should have both directories listed here.
To link the ExampleLibrary target to the executable, you can simply use the target name in target_link_libraries(). There is no need to list out the binary directory (unless you are linking other libraries from there).
So with this in mind, the ExampleApp CMake file could look something like this:
add_executable(ExampleApp
main.cpp
)
target_include_directories(ExampleApp PRIVATE
${PROJECT_SOURCE_DIR}/ExampleLibrary
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(ExampleApp PRIVATE
ExampleLibrary
)

How to clone, build, and link g2o framework in C++

I want to use g2o library in my C++11 project on Ubuntu 18.04, but I cannot make build working. I have all the dependencies. But I cannot link g2o library to my project via CMakeLists.txt
I am a newbie in C++ dependencies.
I've tried cloning https://github.com/RainerKuemmerle/g2o repository and building it with cmake.
The structure is as following:
MY_PROJECT
|__ cmake_modules
|__ project_src
|__ CMakeLists.txt
|__ Thirdparty
|____ g2o
|____ bin
|____ build
|____ cmake_modules # findG2O.cmake
|____ lib # .so shared libraries (all of them, like 20)
|____ g2o
|____ core # headers and source files
|____ solvers
|____ types
|____ CMakeLists.txt
I added cmake_modules from inside g2o to the CMakeLists.txt of my_project
and than try to find it with find_package but it is not found.
LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/g2o/cmake_modules)
find_package(G2O REQUIRED)
if(NOT G2O_FOUND)
message(FATAL_ERROR "G2O not found.")
endif()
I left findG2O.cmake untouched as it is in https://github.com/RainerKuemmerle/g2o/blob/master/cmake_modules/FindG2O.cmake
Should I change the findG2O.cmake? I do not really understand what is going on. How should I proceed with building out of the source and linking?
I haven't found precise answer to my problem anywhere on StackOverflow but maybe I just didn't know what I was searching for.
Error message was:
/home/miki/ORB_SLAM2/Thirdparty/g2o/g2o/types/sim3/types_seven_dof_expmap.h:29:10: fatal error: g2o/config.h: No such file or directory #include "g2o/config.h"
When I tried to change to #include "../../config.h" it worked. How can I solve it in CMakeLists so I do not have to change all includes in ThirdParty library?
The config.h is generated after executing the command
cmake ..
in the folder
MY_PROJECT/Thirdparty/g2o/build
, and this file has some information like what type of used floating point or library you try to use. I think such information will be used to modify some code blocks automatically.
By default, the location of file config.h is in the folder
MY_PROJECT/Thirdparty/g2o/build/g2o
Or you can also use the command
make install
to copy this file to the install path.
If your ${CMAKE_PREFIX_INTALL} is /home/user/, then the location of file config.h is in the folder
/home/user/include/g2o
And if you want to find g2o libraries with find_package, then you need to write
set (G2O_ROOT /home/user)
before the find_package.
Finally, add the header path into CMakeLists.txt, like
include_directories(${G2O_INCLUDE_DIR}

CMake install (TARGETS in subdirectories)

Consider the following CMakeLists.txt file:
add_subdirectory(execA)
add_subdirectory(libB)
install(TARGETS execA libB
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
I get the following error:
install TARGETS given target "execA" which does not exist in this
directory
execA and libB have their own CMakeList.txt files and are located under project directory, as well as the build directory I'm running cmake (cmake ..):
project
|------ CMakeList.txt (the one with the code)
|----execA
| \- .cpp, .hpp and CMakelist.txt
|----libB
| \- .cpp, .hpp and CMakelist.txt
|---- lib
|---- bin
\---- build (where I´m commanding: $ cmake ..
How do I fix this error?
According to this bugreport, install(TARGETS) command flow accepts only targets created within the same directory.
So you need either move the add_library() call into the top-level directory, or split install(TARGETS) call into per-target ones, and move each of them into the corresponding subdirectory.
Since CMake 3.13 install(TARGETS) can work even with targets created in other directories.
install(TARGETS) can install targets that were created in other directories. When using such cross-directory install rules, running make install (or similar) from a subdirectory will not guarantee that targets from other directories are up-to-date.
Even though it would help seeing the CMakeLists.txt files contained in the subdirectories, I guess they contain add_executable and/or add_library statements to create your stuff.
Also, because of your example, I guess you are using the same name of your directories for your targets.
That said, you should know that symbols defined in a CMakeLists.txt file in a subdirectory are not visible by default within the context of the CMakeLists.txt file in the parent directory. Because of that, you should rather move your install statements within the CMakeLists.txt files within your subdirectories.
This should solve the problem, if my thoughts were right. Otherwise, I strongly suggest you to post in your question also the content of the other files above mentioned.
Anyway, the error is quite clear.
The file that contains the install statement for the target named X does not contain a target creation statement (add_executable and the others) that gives birth to that target, so it goes on saying that that target does not exist in that directory.
This still seems to be a pain point in CMake 3.11.
In our codebase, we have many targets defined in subdirectories and need to create an assortment of installers with different configurations and (potentially overlapping) combinations of targets.
Here's my solution:
Before calling add_subdirectory in your root CMakeLists.txt file, create a GLOBAL property with the names of the target(s) you want to include in your installer.
Wrap target creation functions (add_executable, etc.) in your own custom functions. Within those functions check if the target is present in the global property, and invoke install accordingly.
That approach allows you to centralize installer configuration.
Also: To support creation of multiple installers, we populate our global list along with other installer properties in separate .cmake files. When we invoke cmake, we pass the name of the installer configuration CMake file as a command-line argument. Our root CMakeLists.txt file simply calls include with that file.