21

I am working on a simulation project: Taking an embedded C codebase from a target platform and trying to simulate it on a Host computer for debugging or single stepping into the code.

OS: Ubuntu Linux 14.04, IDE: CodeLite, Makefile Generator: Cmake. I am confused about how to write CMakeLists.txt for the project. Following is the structure of codebase (it's all written in C):

|ARQSim\  
|-->ARQSim.h  
|-->ARQSim.c  
|-->BaseStationCode\  
|   |->downlink.c  
|   |->neoncopy.c  
|   |->armCore\  
|   |  |->common\  
|   |  |  |->Bsconfig.h  
|   |  |  |->config.h  
|   |  |->MacSource\  
|   |  |  |->lib\  
|   |  |  |  |->arqCommon.h  
|   |  |  |  |->OverTheAir.h  
|   |  |  |->source\  
|   |  |  |  |->beacon.c  
|   |  |  |  |->proxyDhcp.c  
|   |  |  |  |->ARQ\  
|   |  |  |  |  |->arqCommon.c  
|   |  |  |  |  |->arqInterface.c  
|   |  |  |  |  |->fragmentation\  
|   |  |  |  |  |  |->fragBookkeeping.c  
|   |  |  |  |  |  |->fragProcessAck.c  
|   |  |  |  |  |->reassembly\  
|   |  |  |  |  |  |->reasmBookkeeping.c  
|   |  |  |  |  |  |->reasmProcessAck.c

I am totally new to Cmake. I have read up a lot of resources on CMake and threads here on StackOverflow. But I get confused every time. Few questions I have:

  1. Do I need only one CMakeLists.txt at root directory or every directory needs a different CMakeLists.txt file?
  2. How to add the source files recursively in CMakeLists.txt?
  3. What are the basic commands I need to put in CMakeLists.txt for MakeFile generation?

An example based on the structure of code mentioned above would be appreciated.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Kazi Hasan
  • 275
  • 1
  • 4
  • 9
  • The structure listed above seems to be a total mess. You may need to separate it into several projects first. – user7860670 Nov 07 '17 at 16:53
  • Does your target not have a debugger? – Christian Gibbons Nov 07 '17 at 16:58
  • @VTT Yes I agree, the structure is messed up, and I havent posted the whole tree here yet. I wish I had time to organize it, but I need to start debugging asap hence I took the embedded code base as it is. Thanks – Kazi Hasan Nov 07 '17 at 21:19
  • @ChristianGibbons : We do have a debugger on the embedded platform. However, its running on **No-OS-Bare-Metal-while(1)** and debugging is crazy on the platform. Target platform(OMAP) depends on continuous interrupt feedback from an Onboard FPGA and DSP. Single Stepping stops this feedback (Wireless Modulation stops, Hence no feedback from DSP). The edge case I want to debug, needs the wireless modulation always turned on. Thats why we are trying to simulate the scenario on host PC and single stepping into it. – Kazi Hasan Nov 07 '17 at 21:32

2 Answers2

37

Do I need only one CMakeLists.txt at root directory or every directory needs a different CMakeLists.txt file?

You would typically have one at each level of the tree where it makes sense

eg:

root/
+--- CMakeLists.txt             // your root CMakeLists
+--- foo/
|    +--- CMakeLists.txt        // foo component's CMakeLists
|    +--- foo.c
|    +--- tests/
|         +--- CMakeLists.txt   // foo test's CMakeLists
|         +--- foo_tests.c
+--- bar/
     +--- CMakeLists.txt        // bar component's CMakeLists
     +--- bar.c
     +--- bar_impl/             // no CMakeLists for this dir, it is part of bar
     |    +--- bar_impl.c
     +--- tests/
          +--- CMakeLists.txt   // bar test's CMakeLists
          +--- bar_tests.c

Project root CMakeLists.txt:

In your project root CMakeLists.txt you specify minimum cmake requirement, the project name, and include the subdirectories which have your various components in them

root/CMakeLists.txt:

cmake_minimum_required (VERSION 3.5)
project (my_project C)

add_subdirectory(foo)
add_subdirectory(bar)

Component CMakeLists.txt:

Then in each component subdirectory, you have another CMakeLists.txt file where you add libraries, executables etc

root/foo/CMakeLists.txt:

add_library(foo foo.c)
target_include_directories(foo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

add_subdirectory(tests)

root/foo/tests/CMakeLists.txt:

add_executable(foo_test foo_tests.c)
target_link_libraries(foo_test foo)

You follow this structure for bar etc...

root/bar/CMakeLists.txt:

add_library(bar 
    bar.c 
    bar_impl/bar_impl.c)
target_include_directories(bar PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(bar foo)

add_subdirectory(tests)

root/bar/tests/CMakeLists.txt:

add_executable(bar_test bar_tests.c)
target_link_libraries(bar_test bar)

Generating build files:

To bootstrap your build, you point cmake at your root/CMakeLists.txt

cd root
mkdir build
cd build
cmake ..

(or use your ide's build manager to generate its build configuration)

Further reading

For details on the various functions I've used here, consult the documentation:

Finally, to answer your second question:

How to add the source files recursively in CMakeLists.txt?

This is not recommended (see this discussion for further details).

It is better to explicitly list each file you want to include in your target.

Note that if you have source files in several separate directories, yet they all belong in the same logical target, then you don't need a CMakeLists.txt file for each directory - just list the subdirectory in the filename

Example:

foo/
+--- foo.c
+--- bar.c
+--- baz/
     +--- baz.c
     +--- bang.c

If you want a single target foo for all the above files, you would create it as follows:

add_library(foo 
   foo.c
   bar.c
   baz/baz.c
   baz/bang.c)

Or if you really wanted to use a variable to store the list of SRCS

set(SRCS 
   foo.c
   bar.c
   baz/baz.c
   baz/bang.c)

add_library(foo ${SRCS})
Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
  • Thanks Steve for the detailed clarification. Its much more clear to me now. Now I have somewhere to start from, along with the documentation you provided, hopefully I will be able to dig in quickly. Really appreciate your feedback. – Kazi Hasan Nov 07 '17 at 21:17
  • @Steve : Can i know what is this `project (my_project C)` line indicate? – Akshay Raiyani Apr 04 '19 at 13:24
  • @AkshayRaiyani it's the [`project`](https://cmake.org/cmake/help/latest/command/project.html) definition - `my_project` is the name of the project (accessible in variable `${PROJECT_NAME}`, and used by some build systems such as Visual Studio.) The `C` indicates this project is a C language project (you could also use, eg, `CXX` to denote a C++ language project). It is required by cmake that the top level `CMakeLists.txt` for a project must include a literal call to this – Steve Lorimer Apr 09 '19 at 13:52
1

I was also looking for a more general way of adding CMakeLists.txt files to my projects. I decided to write a CMake generator (partly because I wanted to understand how CMake works):

https://github.com/Aenteas/cmake-generator

It has a couple of additional features such as creating python wrappers (SWIG).

Writing a generator that suits everyone is impossible but I hope it will give you an idea in case you want to make your customized version.