3

I am going back-and-forth with this confusing concept of CMake. I have read a few articles describing how to write CMake file(s). But I found very less explaination for it.

Point 1 - Do I have to make separate CMakeLists.txt for each folder (Yes, let's call it a folder for simplicity)?

Point 2 - Apparently Answer to Point 1 is NO. I found these commands to automate the search for *.cpp files

# get all *.cpp files recursively
file(GLOB_RECURSE SRC_LIST *.c* *.h*)

Point 3 - There seems no need of mentioning *.hpp file. (This is vague point)

I have tried compiling THE SIMPLEST Hello World! program

CMakeLists.txt
src
| - main.cpp (here I included #include "XYZ/abc.hpp")
| - XYZ
    | - abc.cpp (included #include "XYZ/abc.hpp")
    | - abc.hpp

And the CMake for this was

cmake_minimum_required(VERSION 3.10)
project(CMAkeSample)
add_executable(hello src/main.cpp src/XYZ/abc.cpp)

That suggest, add all .cpp files along with path in the add_executable and we are done. Is this true?

Point 4 - Now I have a comparitively bigger project (developed in eclipse for whatever reason). But I need to make cmake file for it and thus not use the eclipse for building.

below is the file system and I want to make CMakeLists.txt just once (if possible)

CMakeLists.txt
src
| - main.cpp (here I included #include "File0.hpp" and #include "Folder1/File1.hpp")
| - File0.cpp (here I included #include "File0.hpp")
| - File0.hpp (here I included #include "Folder1/File1.hpp" and #include "Folder2/File2.hpp")
| - Folder1
    | - File1.cpp (included #include "File1.hpp")
    | - File1.hpp
| - Folder2
    | - File2.cpp (included #include "File2.hpp")
    | - File2.hpp

So now How to get all the .cpp files without manually writing cmake in each folder. Any suggestions?

UPDATE 1: I have added the CMakeLists.txt like shown

ProjectFolder
    CMakeLists.txt
    src
    | - CMakeLists.txt
    | - main.cpp (here I included #include "File0.hpp" and #include "Folder1/File1.hpp")
    | - File0.cpp (here I included #include "File0.hpp")
    | - File0.hpp (here I included #include "Folder1/File1.hpp" and #include "Folder2/File2.hpp")
    | - Folder1
        | - CMakeLists.txt
        | - File1.cpp (included #include "File1.hpp")
        | - File1.hpp
    | - Folder2
        | - CMakeLists.txt
        | - File2.cpp (included #include "File2.hpp")
        | - File2.hpp

In ProjectFolder > src > CMakeLists.txt

add_library(main main.cpp File0.cpp File0.hpp)
target_link_libraries(main File1)

In ProjectFolder > src > File1 > CMakeLists.txt

add_library(File1 File1.cpp File1.hpp)
target_link_libraries(File1 File2)

In ProjectFolder > src > File > CMakeLists.txt

add_library(File2 File2.cpp File2.hpp)

After this all, I am getting the error as,

-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/ProjectFolder
[ 33%] Built target main
[ 44%] Building CXX object CMakeFiles/ProjectFolder.dir/src/main.cpp.o
[ 55%] Linking CXX executable ProjectFolder
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: cannot find -lFile1

UPDATE 2:

Moving on, To make this work, Few changes here and there were made (as summarised in UPDATE 1 and added linking manually in the Project Folder's CMakeLists.txt as

set(GCC_LINK_FLAGS "-lpthread -lcurl -lgobject-2.0 -lgstreamer-1.0 -lglib-2.0 -lssl -lcrypto -lboost_thread -lboost_system")
add_subdirectory(src)
add_subdirectory(src/Folder1)
add_subdirectory(src/Folder2)

add_executable(ProjectFolder src/main.cpp)
target_link_libraries(ProjectFolder main ${GCC_LINK_FLAGS})

Program executes perfectly. But obviously this is very crude way of writing the linkings. Looking for the solution to Point2.

RC0993
  • 898
  • 1
  • 13
  • 44
  • "How to get all the `.cpp` files without manually writing cmake in each folder?" - You have already shown the solution for that, which uses `file(GLOB_RECURSE)`. So, what do you want from us? – Tsyvarev Feb 01 '19 at 07:27
  • That didnt proerly work for me and I have never worked with cmake, so I have no clue what to ask , so I asked general question. Well as @scheff suggested, I am slowly going through the documents. and writing Cmakes in each subdirectory – RC0993 Feb 01 '19 at 10:10
  • "That didnt properly work for me" - Then you probably need to describe (in the question post), what **exactly** not working in this case, so we could help you in resolving that. – Tsyvarev Feb 01 '19 at 11:02

1 Answers1

2

Point 1 - Do I have to make separate CMakeLists.txt for each folder (Yes, let's call it a folder for simplicity)?

You should make a separate folder for each library or executable. (Although, it's also possible to build multiple projects for executables out of one folder. I sometimes use this option for folders with multiple small test applications.)

For folders with sub-folders you may need a CMakeLists.txt which contains only add_subdirectory() commands. (See example below.)

It's even possible to make a CMakeLists.txt which considers sources from multiple sub-folders. I once wrote an answer concerning this. (SO: Single CMakeLists.txt enough for my project?) Though, look at the votes – there are not many people who consider this as a good idea. ;-)

Point 2 - Apparently Answer to Point 1 is NO. I found these commands to automate the search for *.cpp files

We use it extensively but there are also recommendations to not to do so.

The drawback is that your build chain will not recognize automatically when new sources have been added. If you name all sources explicitly in the CMakeLists.txt, this could be granted.

From CMake doc.:

Note: We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate. The CONFIGURE_DEPENDS flag may not work reliably on all generators, or if a new generator is added in the future that cannot support it, projects using it will be stuck. Even if CONFIGURE_DEPENDS works reliably, there is still a cost to perform the check on every rebuild.

So, using file(GLOB, you shouldn't never forget to re-run CMake explicitly once files have been added, moved, or removed.

Point 3 - There seems no need of mentioning *.hpp file. (This is vague point)

Yes, it's not necessary as include files are mentioned in cpp files. On the other hand, we use CMake with VS2013. It's nice if you find all headers in the resp. VS project folder. So, I would recommend to mention includes as well. (It seems that CMake is clever enough to separate them from sources. So, it will not make build commands for header files.)

Point 4 - Now I have a comparitively bigger project (developed in eclipse for whatever reason). But I need to make cmake file for it and thus not use the eclipse for building.

CMake is a build script builder. We use it to generate VS solutions and projects. I'm sure that it's able to build Makefiles for Linux as well. Unfortunately, I've no practical experience about this. (Actually, this was the reason why we switched to CMake – to have a way for portable building of our portable written source code.


Btw. there is an introduction on cmake.org:

CMake Tutorial


Example:

Imagine the following directory tree for an application myApp:

└─ MyApp/
  ├─ main/
  │ ├─ CMakeLists.txt
  │ └─ myApp.cc
  ├─ gui/
  │ ├─ CMakeLists.txt
  │ ├─ guiMainWindow.cc
  │ └─ guiMainWindow.h
  ├─ model/
  │ ├─ CMakeLists.txt
  │ ├─ model.cc
  │ └─ model.h
  └─ CMakeLists.txt 

The MyApp/CMakeLists.txt isn't responsible for any source code but it collects build scripts of sub-folders. It could look like this:

# MyApp/CMakeLists.txt

# make a project
project(MyApp)
# This will generate a MyApp solution for VisualStudio
# containing all involved projects.

# add sub-folders which have to be considered
add_subdirectory(main)
add_subdirectory(gui)
add_subdirectory(model)

The MyApp/model may provide a library for the basic data model of MyApp without further dependencies. So, MyApp/model/CMakeLists.txt could look like this:

# MyApp/model/CMakeLists.txt

# build rule for library libmodel
add_libary(model
  model.cc model.h)

The MyApp/gui may provide another library for the GUI of MyApp with dependencies to libmodel. MyApp/gui/CMakeLists.txt could look like this:

# MyApp/gui/CMakeLists.txt

# build rule for library libgui
add_libary(gui
  guiMainWindow.cc guiMainWindow.h)

# dependencies
target_link_libraries(gui
  model)

Finally, MyApp/main provides the source code for the main() function of MyApp and builds the executable. MyApp/main/CMakeLists.txt could look like this:

# MyApp/main/CMakeLists.txt

# build rule for executable myApp
add_executable(myApp
  myApp.cc)

# dependencies
target_link_libraries(myApp
  gui model)
Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
  • Hey your answer is very nicely drafted. And thank you for such quick reply. Though I am having a few doubts. `**there are also recommendations to not to do so**` Could you tell me why? `**which contains only addsubdirectory()**` Any example link? – RC0993 Feb 01 '19 at 06:50
  • @RC0993 I edited some additional explanations into answer concerning this (and fixed typos concerning `add_subdirectory()`). ;-) – Scheff's Cat Feb 01 '19 at 07:03
  • I have added subdirectory. in the project root folder's `CMakeLists.txt` like this `add_subdirectory(src/Folder1)`. _Folder1_ contains a blank `CMakeLists.txt` right now. What am I suppose to write in it. I couldn't find an example where `CmakeLists.txt` of Subdirectory is shown. – RC0993 Feb 01 '19 at 10:26
  • 1
    @RC0993 I extended the example (and moved it to the bottom). Though, we are using CMake in production for a long time (with a lot of helper scripts), I just recently started a private project and started from "blank". I used those scripts to prevent the crudest mistakes in my example. Though, the example is untested and I might've overseen something. Btw. my real scripts contain some additional stuff for e.g. building static or shared libraries (in Windows `.lib` or `.dll`) and other definitions for external dependencies like e.g. Qt. I left this out to keep it concise, clear, and small. – Scheff's Cat Feb 01 '19 at 10:49
  • I have created the Cmakes for individual folders and added the linking as shown in the **UPDATE 1** – RC0993 Feb 01 '19 at 12:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/187739/discussion-between-rc0993-and-scheff). – RC0993 Feb 01 '19 at 12:32