下载地址 : https://gitee.com/jeasonb/libmodbus_cmake_test
工作以来用到cmake 已经半年了,现在愈发的感觉到cmake 的强大,今天拿出一些时间将之前用到的一些cmake 的功能整理一下,方便之后自己查阅,同时也给后来者一个参考。
我们使用cmake 大多都是用来编译项目、库等等的用途,接下来我会以libmodbu库为基础介绍如何使用cmake 以及这个开源库用到了cmake 的一些什么功能!
预计将会用cmake 编译libmodbus 库以及测试工程到服务器(x86 在公网)版本 和 嵌入式linux 版本(韦东山老师的imx6ull)
1. 第一步下载到源码
root@jeason:~/work# git clone https://github.com/stephane/libmodbus.git
Cloning into 'libmodbus'...
remote: Enumerating objects: 16, done.
remote: Counting objects: 100% (16/16), done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 4596 (delta 4), reused 7 (delta 4), pack-reused 4580
Receiving objects: 100% (4596/4596), 1.52 MiB | 29.00 KiB/s, done.
Resolving deltas: 100% (3112/3112), done.
root@jeason:~/work# cd libmodbus/
root@jeason:~/work/libmodbus# ls
acinclude.m4 AUTHORS autogen.sh CODE_OF_CONDUCT.md configure.ac CONTRIBUTING.md COPYING.LESSER doc ISSUE_TEMPLATE.md libmodbus.pc.in m4 Makefile.am MIGRATION NEWS README.md src tests
root@jeason:~/work/libmodbus#
2. 打开源码分析
这里我使用的是给服务器装上zerotier 然后和本地的电脑组成虚拟局域网 在虚拟局域网开samba,这样我的电脑就能直接访问到服务器上的文件了。这个无关紧要。总之你要能访问到你自己下载的文件。
观察源码 我们不难发现这个开源项目是给了一个 一键执行脚本的!,所以 我们服务端的升级可以直接运行意见脚本 编译安装库文件,但是 本节主要是记录cmake 的用法,所以还是直接忽略吧,不能偷懒!
分析一下各个目录的用途:
docs 很明显这个目录就是放置各种的使用说明文档的,libmodbus 库非常的友好,所有的api 的说明文档一应俱全!
参考以下图片 这是其中一个API的介绍 介绍了函数原型以及各个参数的意思
m4 路径不知道是干什么用的,所以暂时就不去班门弄斧了,之前的实际项目中也没有用到这个目录
src 目录下就是 各种的库函数的接口,在我们的实际应用中就是把这一部分编译为一个动态库,嵌入式系统在使用的时候就加载这个库文件,这一部分的文件不多 只有那么少数的几个文件!
接着就是test 文件夹了,这个文件夹下面放的是大家喜闻乐见的参考demo ,我的第一个程序也是跑test 来的,有点类似于hello world
最后就是 最外层的各种文件,开源协议等等的文件以及readme 文件,介绍了一些更新记录已知的bug 以及记录了一些牛x的贡献者,向大佬们致敬。
所以我们今天要做的就是创建一个cmake 工程把libmodbus 库 从代码变为可以在不同平台上执行的可执行程序!
3. 创建cmake 工程
使用之前不要忘了装上cmake!
linux 下 (没换源的建议换源!)参考链接https://developer.aliyun.com/mirror/ubuntu
root@jeason:~/work/libmodbus/build# cmake ..
Command 'cmake' not found, but can be installed with:
apt install cmake
root@jeason:~/work/libmodbus/build# sudo apt install cmake
在工程顶层 创建以下几个目录
build – 存放编译中间文件
bin – 存放编译生成的最终文件
cmake – 存放cmake 配置文件
CMakeLists.txt – cmake配置文件 具体如何称呼不知道,就是用于之后生成makefile 的
然后将之前的一份测试的cmake 复制进去,测试的cmake大概是这样的
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
# Set project information
project(libmodbus_cmake VERSION 1.0.1 LANGUAGES CXX)
cmake_minimum_required(VERSION 3.1 FATAL_ERROR) #
# Set project information
project(libmodbus LANGUAGES C) # 设置语言
include(cmakes/BuildDefaults.cmake) #一些编译选项 类似于配置的头文件
include_directories( #添加头文件包含路径
.
./src/
)
add_library(modbus SHARED #关键步骤,设置动态库的文件
./src/modbus-data.c
./src/modbus-tcp.c
./src/modbus-rtu.c
./src/modbus.c
)
include_directories("${PROJECT_SOURCE_DIR}/src/")
编译之后会发现 我们缺少一个配置文件! config.h
这种情况就是因为我们没有按照官方的步骤 运行官方的脚本生成config.h 文件!
那么 就运行一下试试呗
缺少config的报错如下:
root@jeason:~/work/libmodbus/build# cmake..
cmake..: command not found
root@jeason:~/work/libmodbus/build# cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: /root/work/libmodbus/build
root@jeason:~/work/libmodbus/build# make
[ 20%] Building C object CMakeFiles/modbus.dir/src/modbus-data.c.o
/root/work/libmodbus/src/modbus-data.c:24:10: fatal error: config.h: No such file or directory
#include <config.h>
^~~~~~~~~~
compilation terminated.
CMakeFiles/modbus.dir/build.make:62: recipe for target 'CMakeFiles/modbus.dir/src/modbus-data.c.o' failed
make[2]: *** [CMakeFiles/modbus.dir/src/modbus-data.c.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/modbus.dir/all' failed
make[1]: *** [CMakeFiles/modbus.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
运行autogen 和 .config 之后 果然出现了config.h 文件! 运行脚本的过程如下:
root@jeason:~/work/libmodbus# ls
acinclude.m4 autogen.sh build cmakes configure.ac COPYING.LESSER ISSUE_TEMPLATE.md m4 MIGRATION README.md tests
AUTHORS bin CMakeLists.txt CODE_OF_CONDUCT.md CONTRIBUTING.md doc libmodbus.pc.in Makefile.am NEWS src
root@jeason:~/work/libmodbus# ./autogen.sh
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'build-aux'.
libtoolize: linking file 'build-aux/ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: linking file 'm4/libtool.m4'
libtoolize: linking file 'm4/ltoptions.m4'
libtoolize: linking file 'm4/ltsugar.m4'
libtoolize: linking file 'm4/ltversion.m4'
libtoolize: linking file 'm4/lt~obsolete.m4'
configure.ac:33: installing 'build-aux/compile'
configure.ac:56: installing 'build-aux/config.guess'
configure.ac:56: installing 'build-aux/config.sub'
configure.ac:32: installing 'build-aux/install-sh'
configure.ac:32: installing 'build-aux/missing'
src/Makefile.am: installing 'build-aux/depcomp'
parallel-tests: installing 'build-aux/test-driver'
------------------------------------------------------
Initialized build system. You can now run ./configure
------------------------------------------------------
root@jeason:~/work/libmodbus# ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
***************************************** 这里省略很多!!!!!
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/Makefile
config.status: creating src/modbus-version.h
config.status: creating src/win32/modbus.dll.manifest
config.status: creating tests/Makefile
config.status: creating doc/Makefile
config.status: creating libmodbus.pc
config.status: creating config.h
config.status: creating tests/unit-test.h
config.status: executing depfiles commands
config.status: executing libtool commands
libmodbus 3.1.6
===============
prefix: /usr/local
sysconfdir: ${prefix}/etc
libdir: ${exec_prefix}/lib
includedir: ${prefix}/include
compiler: gcc
cflags: -g -O2
ldflags:
documentation: no
tests: yes
观察这个 config.h 可以发现主要就是一些配置项 应该是之后生成可执行文件的编译前提,我们先不去管它,先用默认的编译出服务器版本的。
此时已经可以使用cmake 编译出动态库文件了
root@jeason:~/work/libmodbus# cd build
root@jeason:~/work/libmodbus/build# cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: /root/work/libmodbus/build
root@jeason:~/work/libmodbus/build#
root@jeason:~/work/libmodbus/build#
root@jeason:~/work/libmodbus/build#
root@jeason:~/work/libmodbus/build# make
[ 20%] Building C object CMakeFiles/modbus.dir/src/modbus-data.c.o
[ 40%] Building C object CMakeFiles/modbus.dir/src/modbus-tcp.c.o
/root/work/libmodbus/src/modbus-tcp.c: In function ‘modbus_tcp_accept’:
/root/work/libmodbus/src/modbus-tcp.c:672:14: warning: implicit declaration of function ‘accept4’; did you mean ‘accept’? [-Wimplicit-function-declaration]
ctx->s = accept4(*s, (struct sockaddr *)&addr, &addrlen, SOCK_CLOEXEC);
^~~~~~~
accept
[ 60%] Building C object CMakeFiles/modbus.dir/src/modbus-rtu.c.o
[ 80%] Building C object CMakeFiles/modbus.dir/src/modbus.c.o
[100%] Linking C shared library libmodbus.so
[100%] Built target modbus
root@jeason:~/work/libmodbus/build#
root@jeason:~/work/libmodbus/build# ls
CMakeCache.txt CMakeFiles cmake_install.cmake libmodbus.so Makefile
此时已经编译出来了 动态库文件 libmodbus.so
接下来 使用以下语句让编译文件定向输出到bin文件下
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) #设置 编译输出文件的位置 CMAKE_RUNTIME_OUTPUT_DIRECTORY是内置宏定义
接下来编译一个简单的测试程序
通过添加 上面标红的代码段 可以生成服务器上的可执行文件。
接下来通过修改 gcc 编译器为交叉编译器可以生成 嵌入式设备上的可执行文件 对应的代码段如下图所示:(注意:笔者环境中已经将 编译器加入环境变量,如果没有添加环境变量也可以直接使用 编译器的绝对路径)
将生成的libmodbus.so 拷贝到开发板的 /lib路径 然后将client_test 加执行权限之后运行,
笔者这里直接将服务器公网IP编进代码中。
=