CMake Learning Summary (Part 2)

Hello everyone, in the last article I shared the first part of the cmake article: CMake Learning Summary (Part 1). Today, I will continue to share more about cmake. Without further ado, let’s get started.

1. Make Good Use of CMake, Be Happy All Day (Even…):

1. For multiple source files, use the command aux_source_directory(dir var):

At the end of the last article, there was a question about what to do when you have multiple source files in the same directory. You can’t manually add all the source files to the third command below, as that would be very inefficient:

cmake_minimum_required(VERSION 2.8)

project(main)

add_executable(main main.c test1.c)

To solve this inefficiency, there is a command in cmake that can completely solve this problem. However, to illustrate the issue, I added two more files: test2.c and test2.h:

root@txp-virtual-machine:/home/txp/test# ls
1               cmake_install.cmake  main.c    test1.h  touch1.c
CMakeCache.txt  CMakeLists.txt       Makefile  test2.c  touch1.h
CMakeFiles      main                 test1.c   test2.h

The content of test2.c is as follows:

#include <stdio.h>
#include "test2.h"

void func1()
{
  printf("i like the cmake\n");
}

The content of test2.h is as follows:

#ifndef _TEST2_H_
#define _TEST2_H_

void func1();

#endif

Finally, the main.c calls the func1 function:

#include <stdio.h>
#include "test1.h"
#include "test2.h"
int main(void)
{
    func1();
    func(8);
    printf("TXP Embedded\n");
    return 0;
}

Now, the focus is on how to use aux_source_directory(dir var) in cmake to solve the above inefficiency problem. Next, we will operate in CMakeLists.txt like this:

cmake_minimum_required(VERSION 2.8)

project(main)

aux_source_directory(. SRC_LIST)

add_executable(main ${SRC_LIST})

Then compile:

root@txp-virtual-machine:/home/txp/test# cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/txp/test

root@txp-virtual-machine:/home/txp/test# make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/main.c.o
[ 50%] Linking C executable main

root@txp-virtual-machine:/home/txp/test# ./main
i like the cmake
the b is 8
TXP Embedded

Explanation:

aux_source_directory(. SRC_LIST) means to add all source files in the current directory to the source list variable. Finally, use add_executable(main ${SRC_LIST}) to process all useful source files into the target file main. However, this method has its drawbacks, as it adds all source files in the current directory to the variable SRC_LIST. If we do not need some unused files (only the required source files are needed), we can operate like this:

cmake_minimum_required(VERSION 2.8)

project(main)

set(SRC_LIST
        ./main.c
        ./test1.c
        ./test2.c
         )

add_executable(main ${SRC_LIST})

This can also be compiled:

root@txp-virtual-machine:/home/txp/test# cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/txp/test
root@txp-virtual-machine:/home/txp/test# make
[100%] Built target main

2. In the above example, we find that the source files in the same directory are quite messy. Therefore, in cmake, there is a rule that allows us to put related source files of the same type in the same directory. For example, I now create two directories test1 and test2 under the test directory, and place test1.c, test1.h, test2.c, and test2.h in these two directories respectively:

root@txp-virtual-machine:/home/txp/test# mkdir -p test1 test2
root@txp-virtual-machine:/home/txp/test# ls
@               CMakeFiles           main      test1    test2
1               cmake_install.cmake  main.c    test1.c  test2.c
CMakeCache.txt  CMakeLists.txt       Makefile  test1.h  test2.h

Then move the related files into these two directories:

root@txp-virtual-machine:/home/txp/test# mv test1.c test1.h test1

root@txp-virtual-machine:/home/txp/test# mv test2.c test2.h test2
root@txp-virtual-machine:/home/txp/test# ls
@  CMakeCache.txt  cmake_install.cmake  main    Makefile  test2
1  CMakeFiles      CMakeLists.txt       main.c  test1

root@txp-virtual-machine:/home/txp/test# tree

├── cmake_install.cmake
├── CMakeLists.txt
├── main
├── main.c
├── Makefile
├── test1
│   ├── test1.c
│   └── test1.h
└── test2
    ├── test2.c
    └── test2.h

Then at this point, we need to modify the rules in CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)

project(main)

include_directories(test1 test2)
aux_source_directory(test1 SRC_LIST)
aux_source_directory(test2 SRC_LIST1)

add_executable(main main.c  ${SRC_LIST} ${SRC_LIST1})

Then the compilation output can also pass:

root@txp-virtual-machine:/home/txp/test# cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/txp/test
root@txp-virtual-machine:/home/txp/test# make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/main.c.o
[ 50%] Building C object CMakeFiles/main.dir/test1/test1.c.o
[ 75%] Building C object CMakeFiles/main.dir/test2/test2.c.o
[100%] Linking C executable main
[100%] Built target main
root@txp-virtual-machine:/home/txp/test# ls
@  CMakeCache.txt  cmake_install.cmake  main    Makefile  test2
1  CMakeFiles      CMakeLists.txt       main.c  test1
root@txp-virtual-machine:/home/txp/test# ./main
i like the cmake
the b is 8
TXP Embedded

Explanation:

Here, a new command appears: include_directories. This command is used to add multiple specified header file search paths to the project, separated by spaces.

In actual development projects, source files are generally placed in the src directory, header files in the include directory, generated object files in the build directory, and the final output elf files in the bin directory. This way, it looks clear at a glance. Haha, more details can be found in the next issue breakdown. That’s all for today’s learning summary. Hope it’s useful to you.

CMake Learning Summary (Part 2)

Leave a Comment