大型工程项目
大型工程一般使用make构建的,了解了相关原理就能解决上述问题。
本文用的工程样例是:https://github.com/sipeed/MaixPy.git
一个工程中的源码文件不计其数,需要有一系列的规则说明:
把这些规则写到一个文件里,就是Makefile。
make是一个命令工具,用于解释Makefile中的指令。
尝试写一个hellloworld的程序
#include
int main(){
printf("hello 峡谷金城武\n");
return 0;
}
当我们想对这个hello.c生成可执行文件,通常采用
gcc hello.c -o hello
我们采用Makefile来编写这段代码,新建文件Makefile:
hello:hello.c
gcc hello.c -o hello
大型工程的makefile文件非常复杂,一般人根本搞不懂,也不会写。有没有简单的方法来生成目标文件呢?
当然有。
如果说make-makefile是一个工程构建系统,cmake就是生成这个构建系统的系统。他可以生成各种IDE的工程文件或解决方案和makefile。
cmake通过读取脚本文件——CMakeLists.txt 中的规则来构建编译系统
举例说明:
生成可运行文件,打印HelloWorld
//main.cpp
#include
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.9)
project(HelloWorld)
set(CMAKE_CXX_STANDARD 11)
add_executable(HelloWorld main.cpp)
2.执行cmake:
(base) andrew@myg-pc:~/src/learncmake$ ls
CMakeLists.txt main.cpp
(base) andrew@myg-pc:~/src/learncmake$ mkdir build
(base) andrew@myg-pc:~/src/learncmake$ cd build/
(base) andrew@myg-pc:~/src/learncmake/build$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ - works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/andrew/src/learncmake/build
(base) andrew@myg-pc:~/src/learncmake/build$ ls
CMakeCache.txt CMakeFiles cmake_install.cmake Makefile
(base) andrew@myg-pc:~/src/learncmake/build$ cd ..
(base) andrew@myg-pc:~/src/learncmake$ ls
build CMakeLists.txt main.cpp
(base) andrew@myg-pc:~/src/learncmake$
cmake之后文件,可以看到build文件夹下自动生成很多makefile相关文件
3.执行make,生成目标文件
(base) andrew@myg-pc:~/src/learncmake/build$ make
Scanning dependencies of target HelloWorld
[ 50%] Building CXX object CMakeFiles/HelloWorld.dir/main.cpp.o
[100%] Linking CXX executable HelloWorld
[100%] Built target HelloWorld
(base) andrew@myg-pc:~/src/learncmake/build$ ls
CMakeCache.txt CMakeFiles cmake_install.cmake HelloWorld Makefile
可见生成了HelloWorld
4.运行HelloWorld
(base) andrew@myg-pc:~/src/learncmake/build$ ./HelloWorld
Hello, World!
(base) andrew@myg-pc:~/src/learncmake/build$
cmake除了生成编译规则,还有其他功能:
# 指定 MathFunctions 库的安装路径
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
通过上面的定制,生成的 Demo 文件和 MathFunctions 函数库 libMathFunctions.o 文件将会被复制到 /usr/local/bin 中,而 MathFunctions.h 和生成的 config.h 文件则会被复制到 /usr/local/include 中。
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
了解了cmake,基本上能用比较简单的方式组织源文件结构了。
系统稍微复杂,又会出现新问题,举个例子:
一套代码有很多模块,lcd、触摸屏、摄像头、SPI、I2C、UART等。其中摄像头模块依赖I2C模块。
这套代码可以运行在N个单板,A单板没有摄像头,不需要编译摄像头模组;B单板需要编译全部模块。
如何灵活配置编译单元?
编译过linux就会知道,make menuconfig可以很方便选择编译单元并且配置相关参数。
make menuconfig使用的就是kconfig
kconfig用来做系统配置,生成配置文件:
make menuconfig生成的配置文件有:
举例说明:
https://github.com/sipeed/MaixPy.git
MaixPy/Kconfig:
mainmenu "C/CPP CMake project framework Kconfig configuration"
menu "Toolchain configuration"
config TOOLCHAIN_PATH
string "toolchain path"
default ""
config TOOLCHAIN_PREFIX
string "toolchain prefix"
default ""
endmenu
menu "Components configuration"
osource "${SDK_PATH}/components/*/Kconfig"
osource "${PROJECT_PATH}/*/Kconfig"
endmenu
工程提供了默认makefile配置文件:MaixPy/projects/maixpy_k210_minimum/config_defaults.mk 。里面是一些默认配置,make menuconfig读取这个文件生成默认菜单选项。
# Toolchain configuration
#
CONFIG_TOOLCHAIN_PATH="/opt/kendryte-toolchain/bin"
CONFIG_TOOLCHAIN_PREFIX="riscv64-unknown-elf-"
# end of Toolchain configuration
# Board config
CONFIG_BOARD_MAIX=y
# CONFIG_BOARD_M5STICK is not set
CONFIG_LCD_DEFAULT_WIDTH=320
CONFIG_LCD_DEFAULT_HEIGHT=240
CONFIG_LCD_DEFAULT_FREQ=15000000
CONFIG_SENSOR_FREQ=24000000
*.cmake:cmake文件,里面是一些set指令,给变量赋值。
set(CONFIG_TOOLCHAIN_PATH "/opt/kendryte-toolchain/bin")
set(CONFIG_TOOLCHAIN_PREFIX "riscv64-unknown-elf-")
set(CONFIG_BOARD_MAIX "y")
set(CONFIG_BOARD_M5STICK "")
set(CONFIG_LCD_DEFAULT_WIDTH "320")
set(CONFIG_LCD_DEFAULT_HEIGHT "240")
set(CONFIG_LCD_DEFAULT_FREQ "15000000")
*.mk:make的配置文件,里面是一些编译变量
# Toolchain configuration
CONFIG_TOOLCHAIN_PATH="/opt/kendryte-toolchain/bin"
CONFIG_TOOLCHAIN_PREFIX="riscv64-unknown-elf-"
# end of Toolchain configuration
# Board config
CONFIG_BOARD_MAIX=y
# CONFIG_BOARD_M5STICK is not set
CONFIG_LCD_DEFAULT_WIDTH=320
CONFIG_LCD_DEFAULT_HEIGHT=240
CONFIG_LCD_DEFAULT_FREQ=15000000
CONFIG_SENSOR_FREQ=24000000
# end of Board config
*.h:可在make或make之前的menuconfig时生成
#define CONFIG_TOOLCHAIN_PATH "/opt/kendryte-toolchain/bin"
#define CONFIG_TOOLCHAIN_PREFIX "riscv64-unknown-elf-"
#define CONFIG_BOARD_MAIX 1
#define CONFIG_LCD_DEFAULT_WIDTH 320
#define CONFIG_LCD_DEFAULT_HEIGHT 240
#define CONFIG_LCD_DEFAULT_FREQ 15000000
if(CONFIG_COMPONENT_KENDRYTE_SDK_ENABLE)
################# Add include #################
list(APPEND ADD_INCLUDE "include"
"kendryte-standalone-sdk/lib/bsp/include"
"kendryte-standalone-sdk/lib/drivers/include"
"kendryte-standalone-sdk/lib/utils/include"
)
############## Add source files ###############
append_srcs_dir(ADD_SRCS "kendryte-standalone-sdk/lib/bsp")
append_srcs_dir(ADD_SRCS "kendryte-standalone-sdk/lib/drivers")
append_srcs_dir(ADD_SRCS "src")
if(CONFIG_FREERTOS_ENABLE)
append_srcs_dir(ADD_SRCS "kendryte-standalone-sdk/lib/freertos")
append_srcs_dir(ADD_SRCS "kendryte-standalone-sdk/lib/freertos/portable")
不需要改动CMakeList.txt、*.mk和Kconfig
除了makefile+cmake这套构建系统,还有其他构建系统,比如
What is SCons?
SCons is an Open Source software construction tool—that is, a next-generation build tool. Think of SCons as an improved, cross-platform substitute for the classic Make utility with integrated functionality similar to autoconf/automake and compiler caches such as ccache. In short, SCons is an easier, more reliable and faster way to build software.
Ninja is a small build system with a focus on speed. It differs from other build systems in two major respects: it is designed to have its input files generated by a higher-level build system, and it is designed to run builds as fast as possible.