linux+vcpkg+clion+arm64交叉编译aspia

arm64编译器下载

https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads

AArch64 GNU/Linux target (aarch64-none-linux-gnu)

https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz

clion配置

image-20230710161607160

image-20230710161627454

cmake学习

用clion创建cmake项目默认会生成CMakeLists.txt文件

1
2
3
4
5
6
7
8
9
# CMake 最低版本号要求
cmake_minimum_required(VERSION 3.23)
# 项目信息
project(untitled)

set(CMAKE_CXX_STANDARD 20)
# 指定生成目标
add_executable(untitled main.cpp)

多个源文件

1
2
# 指定生成目标
add_executable(Demo main.cc MathFunctions.cc)

唯一的改动只是在 add_executable 命令中增加了一个 MathFunctions.cc 源文件。这样写当然没什么问题,但是如果源文件很多,把所有源文件的名字都加进去将是一件烦人的工作。更省事的方法是使用 aux_source_directory 命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。其语法如下:

aux_source_directory(<dir> <variable>)

1
2
3
4
5
6
7
8
9
10
11
12
# CMake 最低版本号要求
cmake_minimum_required(VERSION 3.23)

# 项目信息
project (untitled)

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)

# 指定生成目标
add_executable(untitled ${DIR_SRCS})

这样,CMake 会将当前目录所有源文件的文件名赋值给变量 DIR_SRCS ,再指示变量 DIR_SRCS 中的源文件需要编译成一个名称为 untitled 的可执行文件。

多目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# CMake 最低版本号要求
cmake_minimum_required(VERSION 3.23)
# 项目信息
project (untitled)

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)

# 添加 math 子目录
add_subdirectory(math)

# 指定生成目标
add_executable(untitled main.cc)

# 添加链接库
target_link_libraries(untitled MathFunctions)

该文件添加了下面的内容: 第3行,使用命令 add_subdirectory 指明本项目包含一个子目录 math,这样 math 目录下的 CMakeLists.txt 文件和源代码也会被处理 。第6行,使用命令 target_link_libraries 指明可执行文件 main 需要连接一个名为 MathFunctions 的链接库 。子目录中的 CMakeLists.txt:

1
2
3
4
5
6
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)

# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})

在该文件中使用命令 add_library 将 src 目录中的源文件编译为静态链接库。

CMake语法

CMakeLists 详解

CMakeLists 变量篇

我们可以使用 SET(set) 来定义变量

语法SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])指令功能 : 用来显式的定义变量 例子 : SET (SRC_LST main.c other.c) 说明: 用变量代替值,例子中定义 SRC_LST 代替后面的字符串。

我们可以使用 ${NAME} 来获取变量的名称。

cmake 常用变量

环境变量名描述
CMAKE_BINARY_DIR, PROJECT_BINARY_DIR, <projectname>_BINARY_DIR如果是 in source 编译,指得就是工程顶层目录,如果是 out-of-source 编译,指的是工程编译发生的目录。PROJECT_BINARY_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。
CMAKE_SOURCE_DIR, PROJECT_SOURCE_DIR, <projectname>_SOURCE_DIR工程顶层目录。
CMAKE_CURRENT_SOURCE_DIR当前处理的 CMakeLists.txt 所在的路径,比如上面我们提到的 src 子目录。
CMAKE_CURRRENT_BINARY_DIR如果是 in-source 编译,它跟 CMAKE_CURRENT_SOURCE_DIR 一致,如果是 out-of-source 编译,他指的是 target 编译目录。
EXECUTABLE_OUTPUT_PATH , LIBRARY_OUTPUT_PATH最终目标文件存放的路径。
PROJECT_NAME通过 PROJECT 指令定义的项目名称。

cmake 系统信息

系统信息变量名描述
CMAKE_MAJOR_VERSIONCMAKE 主版本号,比如 2.4.6 中的 2
CMAKE_MINOR_VERSIONCMAKE 次版本号,比如 2.4.6 中的 4
CMAKE_PATCH_VERSIONCMAKE 补丁等级,比如 2.4.6 中的 6
CMAKE_SYSTEM系统名称,比如 Linux-2.6.22
CMAKE_SYSTEM_NAME不包含版本的系统名,比如 Linux
CMAKE_SYSTEM_VERSION系统版本,比如 2.6.22
CMAKE_SYSTEM_PROCESSOR处理器名称,比如 i686.
UNIX在所有的类 UNIX 平台为 TRUE,包括 OS X 和 cygwin
WIN32在所有的 win32 平台为 TRUE,包括 cygwin

cmake 编译选项

编译控制开关名描述
BUILD_SHARED_LIBS使用 ADD_LIBRARY 时生成动态库
BUILD_STATIC_LIBS使用 ADD_LIBRARY 时生成静态库
CMAKE_C_FLAGS设置 C 编译选项,也可以通过指令 ADD_DEFINITIONS()添加。
CMAKE_CXX_FLAGS设置 C++编译选项,也可以通过指令 ADD_DEFINITIONS()添加。

CMake 常用指令

  • ADD_DEFINITIONS

语法 : ADD_DEFINITIONS(-DENABLE_DEBUG -DABC)

向 C/C++编译器添加 -D 定义. 如果你的代码中定义了#ifdef ENABLE_DEBUG #endif,这个代码块就会生效。

  • ADD_DEPENDENCIES

语法: ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)

定义 target 依赖的其他 target, 确保在编译本 target 之前,其他的 target 已经被构建。

  • AUX_SOURCE_DIRECTORY

语法 : AUX_SOURCE_DIRECTORY(dir VARIABLE)

作用是发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前 cmake 还不能自动发现新添加的源文件。

比如 :

1
2
AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(main ${SRC_LIST})
  • ADD_SUBDIRECTORY

语法 : ADD_SUBDIRECTORY(NAME) 添加一个文件夹进行编译,该文件夹下的 CMakeLists.txt 负责编译该文件夹下的源码. NAME是想对于调用add_subdirectory的CMakeListst.txt的相对路径.

  • find_package

语法 : find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] [components...]] [OPTIONAL_COMPONENTS components...] [NO_POLICY_SCOPE])

查找并从外部项目加载设置。 <PackageName>_FOUND 将设置为指示是否找到该软件包。 找到软件包后,将通过软件包本身记录的变量和“导入的目标”提供特定于软件包的信息。 该QUIET选项禁用信息性消息,包括那些如果未找到则表示无法找到软件包的消息REQUIRED``。REQUIRED如果找不到软件包,该选项将停止处理并显示一条错误消息。

COMPONENTS选件后(或REQUIRED选件后,如果有的话)可能会列出所需组件的特定于包装的列表 。后面可能会列出其他可选组件OPTIONAL_COMPONENTS。可用组件及其对是否认为找到包的影响由目标包定义。

  • include_directories

语法 : include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

将给定目录添加到编译器用来搜索包含文件的目录中。相对路径被解释为相对于当前源目录。

包含目录添加到 INCLUDE_DIRECTORIES 当前CMakeLists文件的目录属性。它们也被添加到INCLUDE_DIRECTORIES当前CMakeLists文件中每个目标的target属性。目标属性值是生成器使用的属性值。

  • link_libraries

语法 : link_libraries([item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)

将库链接到以后添加的所有目标。

  • ADD_EXECUTABLE

语法 : ADD_EXECUTABLE(<name> [source1] [source2 ...])

利用源码文件生成目标可执行程序。

  • ADD_LIBRARY

语法 : ADD_LIBRARY(<name> [STATIC | SHARED | MODULE] [source1] [source2 ...])

根据源码文件生成目标库。

STATIC,SHARED 或者 MODULE 可以指定要创建的库的类型。 STATIC库是链接其他目标时使用的目标文件的存档。 SHARED库是动态链接的,并在运行时加载

  • ENABLE_TESTING

语法: ENABLE_TESTING().

控制 Makefile 是否构建 test 目标,涉及工程所有目录。 一般情况这个指令放在工程的主CMakeLists.txt 中.

  • ADD_TEST

语法 : ADD_TEST(testname Exename arg1 arg2 ...)

testname 是自定义的 test 名称,Exename 可以是构建的目标文件也可以是外部脚本等等。 后面连接传递给可执行文件的参数。 如果没有在同一个 CMakeLists.txt 中打开ENABLE_TESTING()指令, 任何 ADD_TEST 都是无效的。

  • CMAKE_MINIMUM_REQUIRED

语法 : CMAKE_MINIMUM_REQUIRED 定义 cmake 的最低兼容版本 比如 CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR) 如果 cmake 版本小与 2.5,则出现严重错误,整个过程中止。

  • EXEC_PROGRAM

在 CMakeLists.txt 处理过程中执行命令,并不会在生成的 Makefile 中执行。 具体语法为:

1
2
3
4
EXEC_PROGRAM(Executable [directory in which to run]
[ARGS <arguments to executable>]
[OUTPUT_VARIABLE <var>]
[RETURN_VALUE <var>])

用于在指定的目录运行某个程序,通过 ARGS 添加参数,如果要获取输出和返回值,可通过OUTPUT_VARIABLE 和 RETURN_VALUE 分别定义两个变量.

这个指令可以帮助你在 CMakeLists.txt 处理过程中支持任何命令,比如根据系统情况去修改代码文件等等。

  • FILE 指令

文件操作指令

语法:

1
2
3
4
5
6
7
8
9
10
11
FILE(WRITE filename "message to write"... )
FILE(APPEND filename "message to write"... )
FILE(READ filename variable)
FILE(GLOB variable [RELATIVE path] [globbing expression_r_rs]...)
FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expression_r_rs]...)
FILE(REMOVE [directory]...)
FILE(REMOVE_RECURSE [directory]...)
FILE(MAKE_DIRECTORY [directory]...)
FILE(RELATIVE_PATH variable directory file)
FILE(TO_CMAKE_PATH path result)
FILE(TO_NATIVE_PATH path result)

CMake 控制指令

  • IF 指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()

#####

IF(var),如果变量不是:空,0,N, NO, OFF, FALSE, NOTFOUND 或<var>_NOTFOUND 时,表达式为真。
IF(NOT var ),与上述条件相反。
IF(var1 AND var2),当两个变量都为真是为真。
IF(var1 OR var2),当两个变量其中一个为真时为真。
IF(COMMAND cmd),当给定的 cmd 确实是命令并可以调用是为真。
IF(EXISTS dir)或者 IF(EXISTS file),当目录名或者文件名存在时为真。
IF(file1 IS_NEWER_THAN file2),当 file1 比 file2 新,或者 file1/file2 其中有一个不存在时为真,文件名请使用完整路径。
IF(IS_DIRECTORY dirname),当 dirname 是目录时,为真。
IF(variable MATCHES regex)
IF(string MATCHES regex)
  • FOREACH 指令

语法:

1
2
3
foreach(<loop_var> <items>)
<commands>
endforeach()

其中<items>是以分号或空格分隔的项目列表。记录foreach匹配和匹配之间的所有命令endforeach而不调用。 一旦endforeach评估,命令的记录列表中的每个项目调用一次<items>。在每次迭代开始时,变量loop_var将设置为当前项的值。

  • WHILE 指令

语法:

1
2
3
while(<condition>)
<commands>
endwhile()

while和匹配之间的所有命令 endwhile()被记录而不被调用。 一旦endwhile()如果被评估,则只要为<condition>真,就会调用记录的命令列表。


实战

多个目录,多个源文件

  • 文件部署:
1
2
3
4
5
6
7
8
9
./Demo3
|
+--- main.cc
|
+--- math/
|
+--- MathFunctions.cc
|
+--- MathFunctions.h
  • 顶层的 CMakeLists.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo3)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 添加 math 子目录
add_subdirectory(math)
# 指定生成目标
add_executable(Demo main.cc)
# 添加链接库
target_link_libraries(Demo MathFunctions)
  • math 中使用CMakeLists.txt 生成静态库文件:
1
2
3
4
5
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})

添加第三方依赖库

现在工程需要第三方依赖库 jsoncpp :

1
2
3
4
5
6
7
8
./cmake-start
|
+---src/main.cc
+---ext/jsoncpp/
|
+ ---include/
+ ---lib/
+---CMakeLists.txt

CMakeLists :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cmake_minimum_required (VERSION 2.8)

project(cmake)

add_definitions(-std=gnu++11)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

include_directories(${CMAKE_SOURCE_DIR}/ext/jsoncpp/include)
link_directories(${CMAKE_SOURCE_DIR}/ext/jsoncpp/lib)

aux_source_directory(src SRC)

add_executable(demon ${SRC})

target_link_libraries(demon kmsjsoncpp)

自定义编译选项

CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。

例如,可以将 MathFunctions 库设为一个可选的库,如果该选项为 ON ,就使用该库定义的数学函数来进行运算。否则就调用标准库中的数学函数库。

修改 CMakeLists 文件 我们要做的第一步是在顶层的 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
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo4)
# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided math implementation" ON)
# 是否加入 MathFunctions 库
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/math")
add_subdirectory (math)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})

参考资料

CMake 入门实战 HaHack

cmake 常用变量和常用环境变量查表手册 - 博客园

cmake-env-variables(7) — CMake 3.15.0 Documentation

aspia-router&relay

  • 将router&relay单独摘出来进行arm64编译,以便适配到机顶盒设备运行。

关于在linux上编译aspia等问题

因为作者是基于Ubuntu 20.04 and Debian 11.0这两个系统上进行测试和编译的。

博主我只能使用docker进行编译了,博主使用的是Fedora Linux 37 。在使用vcpkg安装asio出现错误。所以需要一个干净的系统环境进行部署aspia需要的依赖。

  • windows编译aspia
  • windows aspia_host 修改为单文件绿色版。
  • linux编译aspia
  • linux-arm64 编译router&relay
  • aspia 无人值守模式,无界面和GUI版本两种
  • aspia后端优化,增加多租户和多用户模式,网络传输速度控制。
  • 数字证书自签

aspia非常适合企业内部使用,也就是只开放客户端:如XXX酒店管理程序绑定aspia,方便进行远程协助。

ubuntu 编译aspia

Ubuntu 20.04
sudo apt update

1
sudo apt install ninja-build autoconf autoconf-archive autopoint python3 bison gperf libgl1-mesa-dev libglu1-mesa-dev libharfbuzz-dev libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-xinerama0-dev libxcb-util-dev libxkbcommon-dev libxkbcommon-x11-dev libatspi2.0-dev libprocps-dev libxdamage-dev libxrandr-dev libpulse-dev flite1-dev libspeechd-dev speech-dispatcher nasm gcc g++ qtcreator
1
sudo apt-get install curl zip unzip tar
1
git clone https://github.com/microsoft/vcpkg.git --depth 1

出现下面的错误

openssl错误

1
2
3
4
5
6
7
8
9
10
-- Using source at /root/vcpkg/buildtrees/openssl/src/nssl-3.1.1-53a8e40f57.clean
openssl requires Linux kernel headers from the system package manager.
They can be installed on Alpine systems via `apk add linux-headers`.
They can be installed on Ubuntu systems via `apt install linux-libc-dev`.

CMake Error at ports/openssl/unix/portfile.cmake:16 (message):
Could not find make. Please install it through your package manager.
Call Stack (most recent call first):
ports/openssl/portfile.cmake:71 (include)
scripts/ports.cmake:147 (include)

根据错误信息,在编译 OpenSSL 时遇到了以下问题:

  1. 缺少 Linux 内核头文件:在 Alpine 系统上,可以使用 apk add linux-headers 命令安装;在 Ubuntu 系统上,可以使用 apt install linux-libc-dev 命令安装。

  2. 缺少 make 工具:请通过你的软件包管理器安装 make。在大多数 Linux 发行版上,可以使用 apt install make 命令来安装 make。

请按以下步骤解决这些问题:

  1. 首先,安装 Linux 内核头文件。如果你正在使用的是 Alpine 系统,请运行 apk add linux-headers 命令。如果你正在使用的是 Ubuntu 系统,请运行 apt install linux-libc-dev 命令。

  2. 其次,在确保已安装 make 工具后,重新编译 OpenSSL。

1
2
3
4
5
6
sudo apt update
sudo apt install make
cd /root/vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install openssl

运行这些命令将更新软件包列表、安装 make 工具,并重新编译并安装 OpenSSL。

ICU错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CMake Error at scripts/cmake/vcpkg_execute_required_process.cmake:112 (message):
Command failed: /usr/bin/autoreconf -vfi
Working Directory: /root/vcpkg/buildtrees/icu/src/c-73_1-src-3575e21c7c.clean/source
Error code: 2
See logs for more information:
/root/vcpkg/buildtrees/icu/autoconf-x64-linux-err.log

Call Stack (most recent call first):
scripts/cmake/vcpkg_configure_make.cmake:630 (vcpkg_execute_required_process)
ports/icu/portfile.cmake:54 (vcpkg_configure_make)
scripts/ports.cmake:147 (include)


error: building icu:x64-linux failed with: BUILD_FAILED
Elapsed time to handle icu:x64-linux: 4.5 s
Please ensure you're using the latest port files with `git pull` and `vcpkg update`.
Then check for known issues at:
https://github.com/microsoft/vcpkg/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+icu
You can submit a new issue at:
https://github.com/microsoft/vcpkg/issues/new?title=[icu]+Build+error&body=Copy+issue+body+from+%2Froot%2Fvcpkg%2Finstalled%2Fvcpkg%2Fissue_body.md

下载依赖组件

``autoreconfisn't magic (though I encounter package maintainers who obviously believe this). When you ranautoreconf, it failed to find theAX_CHECK_COMPILE_FLAGmacro, and produced a corruptconfigure` script. Usually that produces an error/diagnostic message at the same time.

‘AX_CHECK_COMPILE_FLAG` comes from the autoconf archive project, and Debian has a package which provides this, named autoconf-archive. Likely, you forgot to install it:

1
sudo apt-get install autoconf-archive

https://github.com/microsoft/vcpkg/pull/24512

仍然错误无法继续编译。

其实是缺少autoconf-archive

./vcpkg remove asio

./vcpkg install asio

经过上面的步骤即可进行编译成功。