文章目录
- 使用CMake构建一个大型项目工程
- 1. 大型工程目录结构介绍
- 1.1 工程目录结构介绍
- 1.2 工程目录说明(我是这样设计的,你们也可以参考类似这样设计)
- 1.3 最外层CMakeLists.txt说明
- 1.4 业务逻辑中的CMakeLists.txt说明
- 1.4.1 source中的目录结构
- 1.4.2 CMakeLists.txt说明
- 1.5 测试模型中的的CMakeLists.txt说明
-
- 2. 编译脚本说明
- 3. 工程地址
使用CMake构建一个大型项目工程
在上文中,我们已经学会用CMake去构建一个项目。接来下我对这个工程进一步的完善,使其能应用在更加的项目开发当中。构建一个项目工程,首先要知道自己的要用这个工程来做什么。我是一名嵌入式软件开发工程师。日常的开发有如下需求:
- 开发的平台经常更换,有时使用st的芯片,有时使用nxp的芯片,还有国产的芯片等,这些开发平台是经常需要改变。使用这些芯片的时候,我要使用他们的外设接口(如 spi i2c uart )去操作各种传感器。各种传感器都各种类型品牌,比如加速传感器就有几十种,经常需要测试那种比较好和便宜,各种传感器芯片都要编写一个测试单元去测试,除了板载的测试,我们还需要经常网络的测试,各种类型库的测试,,最终单元测试完成后才能加入我的源码中,进行商务逻辑编写。
- 在开发过程中,难免会使用一些库,比如mqtt,curl,json等
- 经常会使用交叉编译工具链编译之后传到对应的硬件平台。这里弄一个编译之后自动传到对应的脚本
要优化好上面的脚本也是很大的工作量,接下来我将给大家介绍一下我自己常用的模型是怎么样的。
1. 大型工程目录结构介绍
1.1 工程目录结构介绍
为了简介,我删除了很多我自己定义的文件夹,留下的都是自己定义的
.
├── bin
│ └── CMake_Project
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ ├── cmake_install.cmake
│ ├── install_manifest.txt
│ ├── Makefile
│ └── source
├── buildcfg
├── build.sh
├── CMakeLists.txt
├── doc
│ └── README.md
├── log
│ └── README.md
├── README.md
├── script
│ └── README.md
├── source
│ ├── CMakeLists.txt
│ ├── main.cpp
│ └── System_Frame
├── third_lib
│ └── mqtt_lib
└── unit_test
├── board_test
└── net_test
1.2 工程目录说明(我是这样设计的,你们也可以参考类似这样设计)
1.bin
该目录存放着程序的执行文件,如单元测试的执行文件以及总工程项目的执行文件。
2.build
该目录存放CMake构建后的缓存文件。
3.doc
该目录存放工程相关说明文档。
4.script
该目录存放其他辅助的脚本。
5.source
该目录存放主体业务源码。
6.third_lib
该目录存放第三方使用的库。
7.unit_test
该目录存放单元测试工程。
8.CMakeLists.txt
总工程构建CMake文件。
9.build.sh
总工程编译脚本文件。
10.buildcfg
build.sh的配置文件。
11. log
存放修改的详细内容
1.3 最外层CMakeLists.txt说明
cmake_minimum_required(VERSION 3.2.0)
set(LISIN_MTR "CMake_Project")
set(CMAKE_BUILD_TYPE "Debug")
if(CMAKE_BUILD_TYPE STREQUAL Debug)
add_definitions(-D_DEBUG)
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lpthread -std=gnu99 -g -o0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra -g2 -ggdb -o0 -lpthread")
set(SYS_FRAME_H "${CMAKE_SOURCE_DIR}/source/System_Frame")
file(GLOB_RECURSE Mqtt_lib ${THIRLD_LIB_PATH}/mqtt_lib/lib/*.so*)
option(Main_Source "main pro" ON)
option(BOARD_TEST "board_test" OFF)
if(Main_Source)
add_subdirectory(${CMAKE_SOURCE_DIR}/source)
endif()
if(BOARD_TEST)
option(IIC_TEST "UART" OFF)
option(GPIO_TEST "GPIO" OFF)
add_subdirectory(${CMAKE_SOURCE_DIR}/unit_test/board_test)
endif()
1.4 业务逻辑中的CMakeLists.txt说明
1.4.1 source中的目录结构
.
├── CMakeLists.txt
├── main.cpp
└── System_Frame
├── print_cmake.cpp
└── print_cmake.h
1.4.2 CMakeLists.txt说明
aux_source_directory("${PROJECT_SOURCE_DIR}/source/System_Frame" DIR_SOURCE_SYS_FRAME)
aux_source_directory("${PROJECT_SOURCE_DIR}/source" DIR_SOURCE_SRCS)
add_executable( ${LISIN_MTR}
${DIR_SOURCE_SYS_FRAME}
${DIR_SOURCE_SRCS}
)
message(STATUS "SYS_FRAME_H: " ${SYS_FRAME_H})
target_include_directories(${LISIN_MTR} PRIVATE
${SYS_FRAME_H}
)
target_link_libraries(${LISIN_MTR} PUBLIC ${Mqtt_lib})
install(TARGETS ${LISIN_MTR} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/bin)
1.5 测试模型中的的CMakeLists.txt说明
1.51 unit_test中的目录结构
unit_test:这里相当于一个独立的单元,完全由自己编写,不影响主程序,在最外层CMakeLists.txt开关调为ON就编译的这里的程序
.
├── board_test
│ ├── gpio
│ │ └── CMakeLists.txt
│ └── uart
│ └── CMakeLists.txt
└── net_test
2. 编译脚本说明
这个脚本主要的作用是一键编译工程,解决了局域网网内文件的传输,可以可以执行文件放到局域网的目标设备中,对于嵌入式开发会很方便
dirCurrent=`pwd`
dirCompile=$dirCurrent/build
exe_bin_default=lisinmtr
login_usr_default="root"
login_pswd_default="root"
login_ip_default="192.168.1.20"
lisin_bin_path_default="/usr/local/lisin/bin"
rm -rf $dirCompile
mkdir -p $dirCompile
cd $dirCompile
cmake $dirCurrent
cmd_res=$?
if [ $cmd_res -eq 0 ];then
echo "Make \`Makefile\` complete."
make -j4
else
echo "[Err:$cmd_res] \`cmake\` faild."
exit 1
fi
cmd_res=$?
if [ $cmd_res -eq 0 ];then
echo "Compilation complete."
make install
else
echo "[Err:$cmd_res] \`make\` faild."
exit 2
fi
cmd_res=$?
if [ $cmd_res -eq 0 ];then
cd $dirCurrent
cfg_file="$dirCurrent/buildcfg"
if [ ! -f $cfg_file ]; then
echo "touch $cfg_file!!!"
echo "login_user=$login_usr_default" > $cfg_file
echo "login_pswd=$login_pswd_default" >> $cfg_file
echo "login_host=$login_ip_default" >> $cfg_file
echo "exe_bin=$exe_bin_default" >> $cfg_file
echo "dest_path=$lisin_bin_path_default" >> $cfg_file
_exe_bin=$exe_bin_default
_login_user=$login_usr_default
_login_pswd=$login_pswd_default
_login_host=$login_ip_default
_dest_path=$lisin_bin_path_default
else
echo "read buildcfg..."
_login_user=`sed '/^login_user=/!d;s/.*=//;s/\r//g' $cfg_file`
_login_pswd=`sed '/^login_pswd=/!d;s/.*=//;s/\r//g' $cfg_file`
_login_host=`sed '/^login_host=/!d;s/.*=//;s/\r//g' $cfg_file`
_exe_bin=`sed '/^exe_bin=/!d;s/.*=//;s/\r//g' $cfg_file`
_dest_path=`sed '/^dest_path=/!d;s/.*=//;s/\r//g' $cfg_file`
if [ "$_exe_bin" = "" ]; then
echo "login_user=$login_usr_default" >> $cfg_file
_exe_bin=$exe_bin_default
fi
if [ "$_login_user" = "" ]; then
echo "login_pswd=$login_pswd_default" >> $cfg_file
_login_user=$login_usr_default
fi
if [ "$_login_pswd" = "" ]; then
echo "login_host=$login_ip_default" >> $cfg_file
_login_pswd=$login_pswd_default
fi
if [ "$_login_host" = "" ]; then
echo "exe_bin=$exe_bin_default" >> $cfg_file
_login_host=$login_ip_default
fi
if [ "$_dest_path" = "" ]; then
echo "dest_path=$lisin_bin_path_default" >> $cfg_file
_dest_path=$lisin_bin_path_default
fi
fi
exe_bin="${_exe_bin}"
login_user="${_login_user}"
login_pswd="${_login_pswd}"
login_host="${_login_host}"
dest_path="${_dest_path}"
while getopts ":u:p:i:s:h:" opt
do
case $opt in
u)
login_user=$OPTARG
;;
p)
login_pswd=$OPTARG
;;
i)
login_host=$OPTARG
;;
s)
exe_bin=$OPTARG
;;
h)
dest_path=$OPTARG
;;
?)
echo "args error,using default args!!!!"
;;
esac
done
if [ "$exe_bin" != "$_exe_bin" ]; then
echo "replace exe_bin!"
sed -i "/^exe_bin=/c\exe_bin=${exe_bin}" $cfg_file
fi
if [ "$login_user" != "$_login_user" ]; then
echo "replace login_user!"
sed -i "/^login_user=/c\login_user=${login_user}" $cfg_file
fi
if [ "$login_pswd" != "$_login_pswd" ]; then
echo "replace login_pswd!"
sed -i "/^login_pswd=/c\login_pswd=${login_pswd}" $cfg_file
fi
if [ "$login_host" != "$_login_host" ]; then
echo "replace login_host!"
sed -i "/^login_host=/c\login_host=${login_host}" $cfg_file
fi
if [ "$dest_path" != "$_dest_path" ]; then
echo "replace dest_path!"
sed -i "/^dest_path=/c\dest_path=${dest_path}" $cfg_file
fi
dirbin=${dirCurrent}/bin/${exe_bin}
exe_bin_bkp=${exe_bin}_bkp
which "sshpass" > /dev/null
if [ $? == 0 ]; then
echo "\`sshpass\` Installed. Start copy file..."
else
sudo apt-get -y install sshpass
fi
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo "Copying $dirbin to $login_user@$login_host[$login_pswd]:$dest_path ..."
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
sshpass -p $login_pswd ssh -o StrictHostKeyChecking=no $login_user@$login_host "mkdir -p $dest_path"
sshpass -p $login_pswd ssh -o StrictHostKeyChecking=no $login_user@$login_host "mv $dest_path/$exe_bin $dest_path/$exe_bin_bkp"
sshpass -p $login_pswd scp -o StrictHostKeyChecking=no "$dirbin" $login_user@$login_host:"$dest_path"
else
echo "[Err:$cmd_res] \`make\` faild."
exit 3
fi
3. 工程地址
- 我在github上已经分享了我的工程,欢迎指出问题也可以提出优化空间,文档中可能讲的不系,但是CMake的语法比较简单,不懂的可以查一下资料,或者看看我上一篇文章,基本都有介绍到。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)