XuQi's Blog

  • 首页

  • 归档

hostapd_dhcpd

发表于 2019-09-20 更新于 2019-10-20

网卡选择

不同于windows上,大部分的网卡都支持软AP ,linux下的网卡需要支持mode master的才可以做软AP 。具体识别方法如下

1、iwconfig识别

1
2
3
iwconfig wlxec888fbd5d61 mode master
Error for wireless request "Set Mode" (8B06) :
SET failed on device wlxec888fbd5d61 ; Invalid argument.

2、iw识别

上面的操作失败,证明不支持。再进行进一步的验证,有些新的网卡用的是mac80211 framework,对于这些网卡的话,用iwconfig来测试它是否支持master模式是行不通的。

因为他们是使用新的 nl80211接口在用户空间通信的。再使用iw命令进行测试:

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]$ sudo  iw list
........略........................
Supported interface modes:
* IBSS
* managed
* AP
* AP/VLAN
* monitor
* mesh point
* P2P-client
* P2P-GO

如果「Supported interface modes」中有「AP」的话,那么恭喜你,你的无线网卡可以架设虚拟AP 。如果没有则不支持。

3、驱动识别

1
2
3
4
5
6
7
8
9
10
11
root@XuQi:~/proj/Private# ethtool -i wlxec888fbd5d61
driver: rtl8192cu
version: 4.15.0-60-generic
firmware-version: N/A
expansion-rom-version:
bus-info: 2-6:1.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no

例如上面的示例中使用的驱动为rtl8192cu,通过http://wireless.kernel.org/en/users/Drivers AP模式支持的驱动列表里的查找AP项为yes,证明其支持。

1568948144309

即然如此,如何在未购买网卡前选择一款一定支持的网卡呢?wireless.kernel.org也给我们提供了一个方法 ,通过http://wireless.kernel.org/en/users/Devices 硬件列表
(该页按pci、usb、pcmcia接口类型做了区分,点开相应的类型即可查看具体的硬件)。当然,这个表里列出的并不完全,也并不能保证是最适合做软AP的硬件 。是否识合请参查看上面的三个方法。

编译hostapd

编译依赖libnl-3.2.25

http://lists.infradead.org/pipermail/libnl/2014-July/001549.html

下载:http://www.infradead.org/~tgr/libnl/files/libnl-3.2.25.tar.gz

编译依赖openssl

https://www.openssl.org/source/

下载:https://www.openssl.org/source/openssl-1.0.2t.tar.gz

编译hostapd

http://w1.fi/hostapd/

下载:http://w1.fi/releases/hostapd-2.9.tar.gz

hostapd-rtl871xdrv补丁
1
git clone http://www.github.com/pritambaral/hostapd-rtl871xdrv
1
2
3
4
5
6
7
8
9
10
11
Configuration file: hostapd.conf
drv->ifindex=4
l2_sock_recv==l2_sock_xmit=0x0x1130410
ioctl[SIOCSIWMODE]: Invalid argument
Could not set interface to mode(3)!
Could not set interface to master mode!
rtl871xdrv driver initialization failed.
wlxec888fbd5d61: interface state UNINITIALIZED->DISABLED
wlxec888fbd5d61: AP-DISABLED
wlxec888fbd5d61: CTRL-EVENT-TERMINATING
hostapd_free_hapd_data: Interface wlxec888fbd5d61 wasn't started

这个问题的出现是由于你的kernel内核没有配置对wifi的master模式的支持(即对AP热点的支持),解决这个问题的办法就是用make menuconfig打开图形界面,然后选择IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)这个选项;这个选择的地址可以参考WG217 wifi模块RTL8811CU的移植(linux)这篇博客里面的第三部分:RTL8821CU驱动所需的支持中的第2小点:master的选项所在位置有详细的讲解。
原文链接:https://blog.csdn.net/weixin_44362642/article/details/88891384

编译wpa_supplicant

http://w1.fi/releases/wpa_supplicant-2.9.tar.gz

添加

1
2
3
4
CFLAGS +=  -I/home/xuqi/hostadp/build/include/libnl3
LIBS += -L/home/xuqi/hostadp/build/lib

CFLAGS += -I/home/xuqi/hostadp/build/include/

编译错误,注释DBUS

1
2
3
4
5
6
# Add support for new DBus control interface
# (fi.w1.hostap.wpa_supplicant1)
#CONFIG_CTRL_IFACE_DBUS_NEW=y

# Add introspection support for new DBus control interface
#CONFIG_CTRL_IFACE_DBUS_INTRO=y
启动:
1
sudo ./wpa_supplicant -i wlxec888fbd5d61 -c ./wpa_supplicant.conf -B
扫描:
1
2
3
sudo wpa_cli -i wlxec888fbd5d61  scan
sudo wpa_cli -i wlxec888fbd5d61 scan_result
sudo wpa_cli -i wlxec888fbd5d61 add_network
连接:

如果要连接加密方式是[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS] (wpa加密),wifi名称是name,wifi密码是:psk。

1
2
3
sudo wpa_cli -i wlxec888fbd5d61 set_network 0 ssid '"dev-xu"'
sudo wpa_cli -i wlxec888fbd5d61 set_network 0 psk '"xuqi9999"'
sudo wpa_cli -i wlxec888fbd5d61 enable_network 0
保存连接:
1
sudo wpa_cli -i wlxec888fbd5d61 save_config
断开连接:
1
sudo wpa_cli -i wlxec888fbd5d61 disable_network 0
分配IP:
1
udhcpc -i wlxec888fbd5d61 -s /etc/udhcpc.script -q

Soft-blocking

输出到sudo rfkill list显示您的网卡是”soft-blocked”。

当无线卡通过内核发信号通知switch-off时,可能会发生这种情况。

请尝试以下步骤:

  1. 在终端中运行:sudo rfkill unblock wifi; sudo rfkill unblock all
  2. 重新运行sudo rfkill list以确认该卡已被解除阻止。
  3. 重启
  4. 再次重新运行sudo rfkill list以确认已保留的解除阻塞。
  5. 重新运行sudo lshw -class network – 您现在应该看到内核已识别(或不识别)无线卡。

如果已识别无线内核模块(不应该说”unclaimed”),则网络管理器现在应该能够看到您的空闲区域中可用的无线网络。

c++基础知识总结

发表于 2019-09-17 更新于 2019-10-20

C++基础知识

指针和引用的区别

  • 是否分配空间
  • 是否需要初始化
  • 是否支持多级
  • 是否可以支持++
  • sizeof的大小
  • 引用是直接访问变量,指针是间接访问
  • 指针需要做类型检查
  • 引用底层是通过指针实现的
  • 作为参数时,引用是传地址,指针实质上是传地址

从汇编层去解释一下引用

1
2
3
4
5
1.	9:          int x = 1;
2. 00401048 mov dword ptr [ebp-4],1
3. 10: int &b = x;
4. 0040104F lea eax,[ebp-4]
5. 00401052 mov dword ptr [ebp-8],eax

lea eax,[ebp-4] 这条语句将x的地址ebp-4放入eax寄存器mov dword ptr [ebp-8],eax 这条语句将eax的值放入b的地址ebp-8中,作用即:将x的地址存入变量b中,所以从汇编层次来看,的确引用是通过指针来实现的。

指针参数传递和引用参数传递

  • 指针传参,实质上是值传递,被调函数的形参会被当做局部变量,在栈中开辟空间,不会影响主调函数的实参。
  • 引用参数,形参也开辟了空间,但存放的是主调函数实参变量的地址。被调函数的对行参操作,实际上是间接寻址。
  • 从编译角度,程序编译的时候,分别将指针和引用添加到了符号表上,符号表记入了变量名和变量所对应的地址。指针变量在符号表对应的地址值,为指针变量的地址,所以可以改变。而引用在符号表对应地址值为引用对象的地址。符号表生成后就不能再改变,所以引用的对象不能修改。

形参和实参的区别

  • 分配内存的生命周期

static的用法和作用

静态变量什么时候初始化

Telematics-Box

发表于 2019-08-22 更新于 2019-10-20

功能

个人免提通话
Telematics常规服务呼叫(Advisor Call)
位置服务
时钟功能
安全功能: a. 按键触发紧急呼叫 b. 碰撞告警通知(气囊爆破通知ACN/预碰撞通知AACN) c. 防盗通知(VTD/CTD) d. 车辆追踪 e. 电子围栏
远程控制 a. 远程上锁/解锁 b. 远程闪灯/鸣笛 c. 远程启动 d. 远程启动抑制 e. 远程车速限制
车辆远程诊断:
车辆数据监控: a. 数据采集上传 b. 车辆数据记录
远程目的地设置
TBT导航
远程刷新 a. 本模块刷新 b. 车内他模块刷新
数据通道 a. 以太网公共无线接入数据路由 b. WIFI热点(b,g,n)
灵活功能配置能力
自诊断
测试工具功能
虚拟顾问

GPS基础知识

发表于 2019-08-20 更新于 2019-10-20

Linux管道pipe

发表于 2019-08-14 更新于 2019-10-20

Linux进程间通信之管道

什么是管道?

管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。

  1. 其本质是一个伪文件(实为内核缓冲区)

  2. 由两个文件描述符引用,一个表示读端,一个表示写端。

  3. 规定数据从管道的写端流入管道,从读端流出。

管道的原理:

管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。

例如:

1
ps -ef | grep init

管道的局限性:

① 数据自己读不能自己写。

② 数据一旦被读走,便不在管道中存在,不可反复读取。

③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。

④ 只能在有公共祖先的进程间使用管道。

pipe调用

创建管道
1
int pipe(int pipefd[2]); 成功:0;失败:-1,设置errno

函数调用成功返回r/w两个文件描述符。无需open,但需手动close。规定:fd[0] → r; fd[1] → w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。

管道创建成功以后,创建该管道的进程(父进程)同时掌握着管道的读端和写端。如何实现父子进程间通信呢?通常可以采用如下步骤:

image-20190814221735897

步骤
  1. 父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。
  2. 父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。
  3. 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。
管道的读写行为

使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):

  1. 如果所有指向管道写端的文件描述符都关闭了(管道写端引用计数为0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。

  2. 如果有指向管道写端的文件描述符没关闭(管道写端引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

  3. 如果所有指向管道读端的文件描述符都关闭了(管道读端引用计数为0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。当然也可以对SIGPIPE信号实施捕捉,不终止进程。具体方法信号章节详细介绍。

  4. 如果有指向管道读端的文件描述符没关闭(管道读端引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。

总结:

① 读管道:

  1. 管道中有数据,read返回实际读到的字节数。
  1. 管道中无数据:

    (1) 管道写端被全部关闭,read返回0 (好像读到文件结尾)

    (2) 写端没有全部被关闭,read阻塞等待(不久的将来可能有数据递达,此时会让出cpu)

② 写管道:

  1. 管道读端全部被关闭, 进程异常终止(也可使用捕捉SIGPIPE信号,使进程不终止)
  1. 管道读端没有全部关闭:

    (1) 管道已满,write阻塞。

    (2) 管道未满,write将数据写入,并返回实际写入的字节数。

树莓派交叉编译

发表于 2019-08-03 更新于 2019-10-20

挂载共享smb

1
2
3
4
sudo apt install cifs-utils 
sudo mount -t cifs //ip/文件夹 /mnt/文件夹 -o username=用户名,password=密码,vers=1.0

sudo mount -t cifs //192.168.1.100/93ee/software /mnt/

Ubuntu 上配置树莓派的交叉编译环境envbuild.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
mkdir -p ~/toolchain
cd ~
if [ $1 == "pi" ]; then
url="https://s3.amazonaws.com/RTI/Community/ports/toolchains/raspbian-toolchain-gcc-4.7.2-linux32.tar.gz"
name="$(pwd)/toolchain/raspbian-toolchain-gcc-4.7.2-linux32"

if [ ! -d "$name" ]; then
wget $url
tar -zxvf raspbian-toolchain-gcc-4.7.2-linux32.tar.gz $name
fi
export PATH=$name/bin:$PATH
export CROSS_COMPILE=arm-raspbian-linux-gnueabi-
export ARCH=arm

fi
cd -

使用方法:

1
. envbuild.sh pi

Ubuntu编译QT

https://blog.csdn.net/christine14122/article/details/83621585

编辑脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/bin/bash
./configure \
-prefix ../qt-output \
-xplatform linux-g++-64 \
-no-static \
-qt-libpng \
-qt-libjpeg \
-qt-zlib \
-no-strip \
-no-framework \
-no-sse2 \
-no-sse3 \
-no-sse4.1 \
-no-sse4.2 \
-no-avx \
-no-avx2 \
-no-avx512 \
-no-mips_dsp \
-no-mips_dspr2 \
-no-icu \
-no-sql-sqlite \
-no-accessibility \
-no-ssl \
-disable-system-proxies \
-no-cups \
-no-gtk \
-no-opengles3 \
-no-xcb \
-no-ico \
-no-opengl \
-no-eglfs \
-no-direct2d \
-no-directfb \
-no-gbm \
-no-kms \
-no-mirclient \
-no-xcb \
-no-xkbcommon-evdev \
-no-xkbcommon-x11 \
-no-doubleconversion \
-enable-linuxfb \
-qt-freetype \
-make libs \
-nomake examples \
-nomake tests \
-nomake tools \
-opensource \
-confirm-license \
-skip qt3d \
-skip qtactiveqt \
-skip qtandroidextras \
-skip qtcanvas3d \
-skip qtcharts \
-skip qtconnectivity \
-skip qtdatavis3d \
-skip qtdeclarative \
-skip qtdoc \
-skip qtgamepad \
-skip qtgraphicaleffects \
-skip qtlocation \
-skip qtmacextras \
-skip qtmultimedia \
-skip qtnetworkauth \
-skip qtpurchasing \
-skip qtquickcontrols \
-skip qtquickcontrols2 \
-skip qtremoteobjects \
-skip qtscript \
-skip qtscxml \
-skip qtsensors \
-skip qtserialbus \
-skip qtserialport \
-skip qtspeech \
-skip qtsvg \
-skip qttools \
-skip qttranslations \
-skip qtvirtualkeyboard \
-skip qtwayland \
-skip qtwebchannel \
-skip qtwebengine \
-skip qtwebglplugin \
-skip qtwebsockets \
-skip qtwebview \
-skip qtwinextras \
-skip qtxmlpatterns \
-skip qtx11extras \
-no-iconv \
-no-harfbuzz \
-no-evdev

树莓派交叉环境编译

配置交叉编译环境
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
mkdir -p ~/toolchain
cd ~
if [ $1 == "pi" ]; then
url="https://s3.amazonaws.com/RTI/Community/ports/toolchains/raspbian-toolchain-gcc-4.7.2-linux32.tar.gz"
name="$(pwd)/toolchain/raspbian-toolchain-gcc-4.7.2-linux32"

if [ ! -d "$name" ]; then
wget $url
tar -zxvf raspbian-toolchain-gcc-4.7.2-linux32.tar.gz $name
fi
export PATH=$name/bin:$PATH
export CROSS_COMPILE=arm-raspbian-linux-gnueabi-
export CC="$CROSS_COMPILE"gcc
export CXX="$CROSS_COMPILE"g++
fi

cd -
修改qmake.conf

复制一份qt-everywhere-opensource-src-5.1.1/qtbase/mkspecs/arm-raspbian-linux-gnueabi-g++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#
# qmake configuration for building with arm-linux-gnueabi-g++
#

MAKEFILE_GENERATOR = UNIX
CONFIG += incremental gdb_dwarf_index
QMAKE_INCREMENTAL_STYLE = sublib

include(../common/linux.conf)
include(../common/gcc-base-unix.conf)
include(../common/g++-unix.conf)

QT_QPA_DEFAULT_PLATFORM=linuxfb

# modifications to g++.conf
QMAKE_CC = arm-raspbian-linux-gnueabi-gcc
QMAKE_CXX = arm-raspbian-linux-gnueabi-g++
QMAKE_LINK = arm-raspbian-linux-gnueabi-g++
QMAKE_LINK_SHLIB = arm-raspbian-linux-gnueabi-g++

# modifications to linux.conf
QMAKE_AR = arm-raspbian-linux-gnueabi-ar cqs
QMAKE_OBJCOPY = arm-raspbian-linux-gnueabi-objcopy
QMAKE_NM = arm-raspbian-linux-gnueabi-nm -P
QMAKE_STRIP = arm-raspbian-linux-gnueabi-strip
load(qt_config)
编写脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh  
tar xvf ../arm-raspbian-linux-gnueabi-g++.tar.gz -C ./qtbase/mkspecs/
./configure -prefix ../qt-output_pi/ \
-opensource \
-release \
-confirm-license \
-xplatform arm-raspbian-linux-gnueabi-g++ \
-no-opengl \
-no-pch \
-shared \
-no-iconv \
-no-xcb \
-nomake examples \
-nomake tests \
-nomake tools \
编译
1
make -j4 && make install

CMake编译QT

发表于 2019-08-01 更新于 2019-10-20

使用CMake编译

开始

使用find_package找到QT库和文件,推荐方法是用target_link_libraries 命令,这个命令回自动的添加头文件目录,编译宏,地址无关代码和链接到qtmain这个库。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
cmake_minimum_required(VERSION 3.1.0)

project(helloworld)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

if(CMAKE_VERSION VERSION_LESS "3.7.0")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()

find_package(Qt5 COMPONENTS Widgets REQUIRED)

add_executable(helloworld
mainwindow.ui
mainwindow.cpp
main.cpp
resources.qrc
)

target_link_libraries(helloworld Qt5::Widgets)

为了find_package成功找到QT5,它必须在 CMAKE_PREFIX_PATH路径下,或者Qt5_DIR下必须有Qt5config.cmake文件。最简单的办法就是设置环境变量CMAKE_PREFIX_PATH为QT的按照目录。

同时CMAKE_AUTOMOC必须设置为ON。

详见https://cmake.org/cmake/help/latest/manual/cmake-qt.7.html#automoc#)

导入模块

引入模块可以像这样 Qt5_LIBRARIES,比如在target_link_libraries. 实际的路径可以通过以下方式获取:

1
2
3
find_package(Qt5 COMPONENTS Core REQUIRED)

get_target_property(QtCore_location Qt5::Core LOCATION)

很少需要知道完整的路径,每一个QT5模块的库,可以用Qt5::方便的使用。

如果你的有自己的CMake文件,你必须设置debug或者release。例如

1
2
3
4
5
6
7
find_package(Qt5 COMPONENTS Core REQUIRED)

set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_RELEASE} -fprofile-arcs -ftest-coverage")

# set up a mapping so that the Release configuration for the Qt imported target is
# used in the COVERAGE CMake configuration.
set_target_properties(Qt5::Core PROPERTIES MAP_IMPORTED_CONFIG_COVERAGE "RELEASE")

导入插件

插件同样支持导入, Qt Network, Qt SQL, Qt GUI, 和 Qt Widgets 模块都有关联的插件,他们都提供了插件列表,在Qt5<Module>_PLUGINS变量中。

1
2
3
4
foreach(plugin ${Qt5Network_PLUGINS})
get_target_property(_loc ${plugin} LOCATION)
message("Plugin ${plugin} is at location ${_loc}")
endforeach()

Qt Core

https://doc.qt.io/qt-5/qtcore-index.html

核心功能

Qt将这些特性添加到C++中:

1.一种非常强大的机制,用于无缝对象通信,称为信号和插槽
2.可查询和可设计的对象属性
3.组织的层次化和可查询的对象树
4.用保护指针(QPointer)的自然方式拥有对象所有权
5.跨库边界的动态转换

线程和并发编程

Qt以独立于平台的线程类的形式提供线程支持,线程安全的发布事件的方式,以及跨线程的信号槽连接。
多线程编程也是一种有用的范例,它可以在不冻结应用程序的用户界面的情况下执行耗时的操作。Qt页面中的线程支持包含在应用程序中实现线程的信息。额外的并发类由Qt并发模块提供。

输入/输出、资源和容器

Qt提供了一种资源系统,用于组织应用程序文件和资产、一组容器和用于接收输入和打印输出的类:

  1. 容器类
  2. 序列化Qt数据类型
  3. 隐式共享
  4. 此外,Qt核心提供了一种独立于平台的机制,用于在应用程序的可执行文件中存储二进制文件。
    Qt的资源系统

额外的框架

Qt Core还提供了Qt的一些关键框架:

  1. 动画框架
  2. 在Qt JSON支持
  3. 状态机框架
  4. 如何创建Qt插件
  5. 事件系统

代码下载

http://download.qt.io/archive/qt/5.13/5.13.0/submodules/

QT和JS交互调用

https://blog.csdn.net/caoshangpa/article/details/51014690

V2X之MATLAB

发表于 2019-07-17 更新于 2019-10-20

C-V2X之ASN.1

发表于 2019-07-17 更新于 2019-10-20

简介

ASN.1 全称 Abstract Syntax Natation One. 是一个用来描述抽象类型抽象数据的语法. 类似于 XML, JSON 等, 主要用于编码数据以便于在网络中交换数据.

在线解析工具:https://lapo.it/asn1js/

ASN.1编码方式

ASN.1 中定义四种类型

  • 简单类型 (Simple types) : 用于编码基本的数据类型. 如 整形,字符串,二进制数据等.

  • 结构类型 (Structured types) : 用于编码复杂数据类型. 如, X509 证书中的公钥.

  • 标记的类型 (Tagged types) : 用于编码从其他几种类型引申而来的类型.

  • 其他类型 (Other types) : CHOICE 或 Any.

阅读全文 »

CMake入门

发表于 2019-07-09 更新于 2019-10-20

CMake管理工程

在Linux平台下使用CMake生成Makefile并编译的流程如下:

  1. 编写CMake配置文件CMakeLists.txt
  2. 执行命令cmake PATH生成Makefile,PATH是CMakeLists.txt所在的目录。
  3. 使用make命令进行编译。

简单讲就是CMake是自动生成Makefile文件的工具

安装CMake

1
sudo apt-get install cmake

创建CMakeLists.txt 骨架

1
2
3
4
5
6
# CMake 最低版本号要求 不写会有警告
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.cpp)

CMakeLists.txt中的编写方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
project(Demo1) # App的名称,需要修改⭐️
cmake_minimum_required(VERSION 2.8)

#加载自定义模块
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
#设置库文件路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
#设置可执行程序路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
#设置子目录
set(SUB_DIR_LIST "Thread" "Util") #需要修改⭐️

#安装目录
set(INSTALL_PATH_LIB lib)
set(INSTALL_PATH_INCLUDE include)


foreach(SUB_DIR ${SUB_DIR_LIST})
#遍历源文件
aux_source_directory(src/${SUB_DIR} SRC_LIST)
#安装头文件至系统目录
install(DIRECTORY src/${SUB_DIR} DESTINATION ${INSTALL_PATH_INCLUDE} FILES_MATCHING PATTERN "*.h")
endforeach()

#或者,搜集文件,并把文件列表赋给ToolKit_src_list
file(GLOB ToolKit_src_list ${ToolKit_Root}/*/*.cpp ${ToolKit_Root}/*/*.h ${ToolKit_Root}/*/*.c)



set(LINK_LIB_LIST)

set(ENABLE_OPENSSL true)

#查找openssl是否安装 需要修改⭐️
find_package(OpenSSL QUIET)
if(OPENSSL_FOUND AND ENABLE_OPENSSL)
message(STATUS "找到openssl库:\"${OPENSSL_INCLUDE_DIR}\",ENABLE_OPENSSL宏已打开")
include_directories(${OPENSSL_INCLUDE_DIR})
add_definitions(-DENABLE_OPENSSL) # 定义宏
list(APPEND LINK_LIB_LIST ${OPENSSL_LIBRARIES})
endif()

#打印库文件
message(STATUS "将链接依赖库:${LINK_LIB_LIST}")

#引用头文件路径
include_directories(${PROJECT_SOURCE_DIR}/src)
#使能c++11
add_compile_options(-std=c++11)# 需要修改⭐️

# 修改其他编译选项
add_compile_options(-Wno-deprecated-declarations)
add_compile_options(-Wno-predefined-identifier-outside-function)


#编译动态库
add_library(${CMAKE_PROJECT_NAME}_shared SHARED ${SRC_LIST})
target_link_libraries(${CMAKE_PROJECT_NAME}_shared ${LINK_LIB_LIST})
set_target_properties(${CMAKE_PROJECT_NAME}_shared PROPERTIES OUTPUT_NAME "${CMAKE_PROJECT_NAME}")
install(TARGETS ${CMAKE_PROJECT_NAME}_shared ARCHIVE DESTINATION ${INSTALL_PATH_LIB} LIBRARY DESTINATION ${INSTALL_PATH_LIB})

#编译静态库
add_library(${CMAKE_PROJECT_NAME}_static STATIC ${SRC_LIST})
set_target_properties(${CMAKE_PROJECT_NAME}_static PROPERTIES OUTPUT_NAME "${CMAKE_PROJECT_NAME}")

#安装静态库至系统目录
install(TARGETS ${CMAKE_PROJECT_NAME}_static ARCHIVE DESTINATION ${INSTALL_PATH_LIB})

#测试程序的目录中也有CMakeLists.txt
add_subdirectory(tests)

测试程序的CMakeList编写方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 执行cp命令
execute_process(COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/ssl.p12 ${EXECUTABLE_OUTPUT_PATH}/)

# 当前目录加入TEST_SRC_LIST
aux_source_directory(. TEST_SRC_LIST)
# 遍历TEST_SRC_LIST
foreach(TEST_SRC ${TEST_SRC_LIST})
# 去掉后缀
STRING(REGEX REPLACE "^\\./|\\.c[a-zA-Z0-9_]*$" "" TEST_EXE_NAME ${TEST_SRC})
message(STATUS "添加测试程序:${TEST_EXE_NAME}")
# 每个cpp作为一个可执行文件
add_executable(${TEST_EXE_NAME} ${TEST_SRC})
# 连接动态库
target_link_libraries(${TEST_EXE_NAME} ${CMAKE_PROJECT_NAME}_shared ${LINK_LIB_LIST} pthread)

endforeach(TEST_SRC ${TEST_SRC_LIST})
cmake find_package的基本原理

比如说,我们需要一个第三方库 curl,那么我们的 CMakeLists.txt 需要指定头文件目录,和库文件,类似

1
2
include_directiories(/usr/include/curl)
target_link_libraries(myprogram path/curl.so)

如果借助于cmake提供的finder会怎么样呢?使用cmake的Modules目录下的FindCURL.cmake,相应的CMakeList.txt 文件:

1
2
3
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIR})
target_link_libraries(curltest ${CURL_LIBRARY})

那么cmake是如何查找的呢?

find_package()命令首先会在模块路径中寻找Find.cmake,这是查找库的一个典型方式。具体查找路径依次为CMake:变量{CMAKE_MODULE_PATH}中的所有目录。如果没有,然后再查看它自己的模块目录/share/cmake-x.y/Modules/($CMAKE_ROOT的具体值可以通过CMake中message命令输出)。这称为模块模式。

为了能支持各种常见的库和包,CMake自带了很多模块。可以通过命令 cmake –help-module-list (输入cmake –help,然后双击Tab会有命令提示)得到你的CMake支持的模块的列表: 直接查看模块路径。比如Ubuntu linux上,模块的路径是 ls /usr/share/cmake/Modules/:

1
2
3
4
5
6
7
8
ll -th /usr/share/cmake-3.5/Modules/
......
-rw-r--r-- 1 root root 76K Sep 27 2016 FindBoost.cmake
-rw-r--r-- 1 root root 2.7K Mar 24 2016 FindCoin3D.cmake
-rw-r--r-- 1 root root 77K Mar 24 2016 FindCUDA.cmake
-rw-r--r-- 1 root root 3.1K Mar 24 2016 FindCups.cmake
-rw-r--r-- 1 root root 2.4K Mar 24 2016 FindCURL.cmake
........

让我们以bzip2库为例。CMake中有个 FindBZip2.cmake 模块。只要使用 find_package(BZip2) 调用这个模块,cmake会自动给一些变量赋值,然后就可以在CMake脚本中使用它们了。变量的列表可以查看cmake模块文件,或者使用命令:

1
2
3
4
5
6
7
8
9
10
11
root@xy:~/cmake_practice/cmake_build/build_demo10# cmake --help-module FindBZip2
FindBZip2
Try to find BZip2

Once done this will define
::
BZIP2_FOUND - system has BZip2
BZIP2_INCLUDE_DIR - the BZip2 include directory
BZIP2_LIBRARIES - Link these to use BZip2
BZIP2_NEED_PREFIX - this is set if the functions are prefixed with BZ2_
BZIP2_VERSION_STRING - the version of BZip2 found (since CMake 2.8.8)
Filesystem
1
2
3
4
5
6
file(GLOB <variable>
[LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
[<globbing-expressions>...])
file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS]
[LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
[<globbing-expressions>...])

产生一个匹配 <globbing-expressions> 的文件列表并将它存储到变量 <variable> 中。文件名替代表达式和正则表达式相似,但更简单。如果 RELATIVE 标志位被设定,将返回指定路径的相对路径。结果将按字典顺序排序。

如果 CONFIGURE_DEPENDS 标志位被指定,CMake 将在编译时给主构建系统添加逻辑来检查目标,以重新运行 GLOB 标志的命令。如果任何输出被改变,CMake都将重新生成这个构建系统。

注意:我们不推荐使用 GLOB 来从源文件树收集源文件列表。如果当源文件添加或删除时没有 CMakeLists.txt 文件被修改,那么在 CMake 重新生成时并不会识别出它们。CONFIGURE_DEPENDS 标志位可能不会再所有生成器上可靠的工作,如果一个新的生成器在以后被添加,并不会被支持。如果项目使用它将会被卡主。即使 CONFIGURE_DEPENDS 可靠的工作,在每个重新构建的过程中做检查也十分浪费性能。

交叉编译配置

1
2
3
4
5
6
7
8
9
10
11
12
SET(TOOLSCHAIN_PATH /home/zero/sdk/gcc-4.6.2-glibc-2.13-linaro-multilib-2011.12/fsl-linaro-toolchain/)
set(TOOLCHAIN_HOST "${TOOLSCHAIN_PATH}bin/arm-none-linux-gnueabi")

set(TOOLCHAIN_CC "${TOOLCHAIN_HOST}-gcc")
set(TOOLCHAIN_CXX "${TOOLCHAIN_HOST}-g++")

# Define the compiler
set(CMAKE_C_COMPILER ${TOOLCHAIN_CC})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_CXX})

#告诉cmake是进行交叉编译
set(CMAKE_CROSSCOMPILING TRUE)

编译传参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
CMake option
使用场景 : 编译脚本传递参数 -> CMake脚本接收option -> 源代码宏

编译脚本传入参数
传入一个cmake option TEST_DEBUG

#!/bin/sh

cmake -DTEST_DEBUG=ON .
cmake --build .


CMake脚本接收option
cmake 脚本定义TEST_DEBUG 默认关闭OFF

project(test)

option(TEST_DEBUG "option for debug" OFF)
if (TEST_DEBUG)
add_definitions(-DTEST_DEBUG)
endif()
...


源代码宏 test.c

#include "test.h"

#ifdef TEST_DEBUG
...
#endif
12…5

XuQi

44 日志
30 标签
© 2019 XuQi
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Muse v7.3.0