Browse code

Docs: add ARM64 cross-compile instructions for Windows and Linux

Micah Snyder authored on 2024/03/27 01:48:11
Showing 3 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,281 @@
0
+# Cross-compiling ClamAV on Linux for arm64
1
+
2
+These are instructions to cross-compile ClamAV on Linux amd64 (`x86_64-unknown-linux-gnu`) with GCC for Linux arm64 (`aarch64-unknown-linux-gnu`).
3
+
4
+> _Note_: These build instructions were written for Ubuntu. You may need to change a few steps to work with your distro.
5
+
6
+## Install build tools, if missing
7
+
8
+Install the GCC/G++ and Rust toolchains needed to cross-compile to aarch64:
9
+
10
+```bash
11
+# Install toolchain
12
+sudo apt install -y g++-aarch64-linux-gnu
13
+rustup target add aarch64-unknown-linux-gnu
14
+```
15
+
16
+## Install build dependencies
17
+
18
+If you have a sysroot for your `aarch64-unknown-linux-gnu` target platform with the required dependencies installed, skip this step. Else, do these things to install arm64 (aarch64) versions of the ClamAV library dependencies on the local host.
19
+
20
+```bash
21
+sudo dpkg --add-architecture arm64
22
+```
23
+
24
+Create a new .list file in `/etc/apt/sources.list.d`:
25
+
26
+```bash
27
+sudo vim  /etc/apt/sources.list.d/arm-cross-compile-sources.list
28
+```
29
+
30
+Add arm64 package sources to this new list:
31
+```
32
+deb [arch=arm64] http://ports.ubuntu.com/ focal main restricted
33
+deb [arch=arm64] http://ports.ubuntu.com/ focal-updates main restricted
34
+deb [arch=arm64] http://ports.ubuntu.com/ focal universe
35
+deb [arch=arm64] http://ports.ubuntu.com/ focal-updates universe
36
+deb [arch=arm64] http://ports.ubuntu.com/ focal multiverse
37
+deb [arch=arm64] http://ports.ubuntu.com/ focal-updates multiverse
38
+deb [arch=arm64] http://ports.ubuntu.com/ focal-backports main restricted universe multiverse
39
+```
40
+
41
+> _Tip_: "focal" is for Ubuntu 20.04LTS. You may need to swap to another to match your release:
42
+> - focal (20.04LTS)
43
+> - jammy (22.04LTS)
44
+> - kinetic (22.10)
45
+> - lunar (23.04)
46
+> - mantic (23.10)
47
+>
48
+> See https://packages.ubuntu.com/ for more.
49
+
50
+Now install the arm64 libraries:
51
+
52
+```bash
53
+apt-get update && apt-get install -y \
54
+  check:arm64 \
55
+  libbz2-dev:arm64 \
56
+  libcurl4-openssl-dev:arm64 \
57
+  libjson-c-dev:arm64 \
58
+  libmilter-dev:arm64 \
59
+  libncurses5-dev:arm64 \
60
+  libpcre2-dev:arm64 \
61
+  libssl-dev:arm64 \
62
+  libxml2-dev:arm64 \
63
+  zlib1g-dev:arm64
64
+```
65
+
66
+After install, the `.a` and `.so` libraries will be found under `/usr/lib/aarch64-linux-gnu/`. The headers are the same as for any other arch, so those will be under `/usr/include/` as per usual.
67
+
68
+## Create a CMake toolchain file
69
+
70
+A CMake toolchain file specifies some toolchain specific variables.
71
+
72
+Note: The `CMAKE_SYSROOT` variable may **not** be set using the `cmake -D CMAKE_SYROOT=PATH` method and must be in this file. Meanwhile, some other variables (namely `CMAKE_INSTALL_PREFIX`) *cannot* be set in the toolchain file, and should be passed as a command parameter.
73
+
74
+## Help Cargo find GCC (possibly needed)
75
+
76
+On some systems, `cargo` does not find the right GCC executable and emits this error:
77
+```
78
+ = note: cc: error: unrecognized command-line option '-m64'
79
+```
80
+
81
+**If** this error occurs during the build, set the following environment variables and then try again:
82
+```sh
83
+export HOST_CC=gcc
84
+export CC_x86_64_unknown_linux_gnu=/usr/bin/x86_64-linux-gnu-gcc
85
+export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=/usr/bin/x86_64-linux-gnu-gcc
86
+```
87
+
88
+> _Note_: Your specific path to and executable name for GCC may vary depending on your platform.
89
+
90
+> _Credit_: [Kornel on Stack Overflow](https://stackoverflow.com/a/72546887/3430496)
91
+
92
+### If using a sysroot
93
+
94
+`CMAKE_TOOLCHAIN_ARM64.cmake`:
95
+```cmake
96
+# Platform
97
+set(CMAKE_SYSTEM_NAME       Linux)
98
+set(CMAKE_SYSTEM_PROCESSOR  arm64)
99
+set(CMAKE_C_COMPILER        "aarch64-linux-gnu-gcc")
100
+set(CMAKE_CXX_COMPILER      "aarch64-linux-gnu-g++")
101
+set(RUST_COMPILER_TARGET    "aarch64-unknown-linux-gnu")
102
+
103
+# Project Variables needed to cross compile
104
+set(HAVE_ATTRIB_ALIGNED     1)
105
+set(HAVE_ATTRIB_PACKED      1)
106
+set(HAVE_UNAME_SYSCALL      1)
107
+set(HAVE_SAR                1)
108
+set(HAVE_FD_PASSING         1)
109
+set(MMAP_FOR_CROSSCOMPILING ON)
110
+set(ENABLE_SYSTEMD          OFF)
111
+
112
+set( test_run_result
113
+     "PLEASE_FILL_OUT-FAILED_TO_RUN"
114
+     CACHE STRING "Result from try_run" FORCE)
115
+
116
+set( test_run_result__TRYRUN_OUTPUT
117
+     "PLEASE_FILL_OUT-NOTFOUND"
118
+     CACHE STRING "Output from try_run" FORCE)
119
+
120
+#
121
+# Dependencies
122
+#
123
+
124
+# If using a sysroot / rootfs for the target, set these.
125
+set(CMAKE_SYSROOT           /opt/aarch64-wrs-linux-sysroot)
126
+
127
+# If your CMAKE_SYSROOT directory is readonly, or for some reason you want to install to a different staging prefix before copying  to your host, set this:
128
+#set(CMAKE_STAGING_PREFIX    /home/user/stage)
129
+
130
+# Note, you may need to set ENABLE_JSON_SHARED if your sysroot provides libjson-c.so instead of libjson-c.a.
131
+#set(ENABLE_JSON_SHARED      ON)
132
+
133
+# You may need to set the following if CMake has some trouble finding the depenencies.
134
+# For example if you have `libjson-c.a` in your sysroot, here: `/opt/aarch64-wrs-linux-sysroot/usr/lib64/libjson-c.a`
135
+# then you would set:
136
+#set(JSONC_LIBRARY           "/usr/lib64/libjson-c.a")
137
+
138
+#
139
+# Uncomment these as needed:
140
+#
141
+#set(JSONC_INCLUDE_DIR       "/usr/include/json-c")
142
+#set(JSONC_LIBRARY           "/usr/lib64/libjson-c.a")
143
+#set(ENABLE_JSON_SHARED      OFF)
144
+
145
+#set(BZIP2_INCLUDE_DIR       "/usr/include/")
146
+#set(BZIP2_LIBRARY           "/usr/lib64/libbz2.a")
147
+
148
+#set(OPENSSL_ROOT_DIR        "/usr/")
149
+#set(OPENSSL_INCLUDE_DIR     "/usr/include/")
150
+#set(OPENSSL_CRYPTO_LIBRARY  "/usr/lib64/libcrypto.so")
151
+#set(OPENSSL_SSL_LIBRARY     "/usr/lib64/libssl.so")
152
+
153
+#set(LIBXML2_INCLUDE_DIR     "/usr/include/libxml2")
154
+#set(LIBXML2_LIBRARY         "/usr/lib64/libxml2.so")
155
+
156
+#set(PCRE2_INCLUDE_DIR       "/usr/include/")
157
+#set(PCRE2_LIBRARY           "/usr/lib64/libpcre2-8.so")
158
+
159
+#set(CURSES_INCLUDE_DIR      "/usr/include/")
160
+#set(CURSES_LIBRARY          "/usr/lib/aarch64-linux-gnu/libncurses.a;/usr/lib/aarch64-linux-gnu/libtinfo.a")
161
+# Tip: You may not need to also link with libtinfo.a, depending on what your distribution provides:
162
+#set(CURSES_LIBRARY          "/usr/lib/aarch64-linux-gnu/libncurses.a")
163
+# Tip: Alternatively, you could link with the shared library:
164
+#set(CURSES_LIBRARY          "/usr/lib/aarch64-linux-gnu/libncurses.so")
165
+
166
+#set(ZLIB_INCLUDE_DIR        "/usr/include/")
167
+#set(ZLIB_LIBRARY            "/usr/lib64/libz.so")
168
+
169
+#set(LIBCHECK_INCLUDE_DIR    "/usr/include/")
170
+#set(LIBCHECK_LIBRARY        "/usr/lib64/libcheck.a")
171
+```
172
+
173
+### If not using a sysroot
174
+
175
+Without a sysroot, you must tell CMake exactly where to find the library dependencies built for aarch64.
176
+
177
+> _IMPORTANT_: Without a sysroot, your runtime platform must have these EXACT SAME libraries.
178
+
179
+`CMAKE_TOOLCHAIN_ARM64.cmake`:
180
+```cmake
181
+# Platform
182
+set(CMAKE_SYSTEM_NAME       Linux)
183
+set(CMAKE_SYSTEM_PROCESSOR  arm64)
184
+set(CMAKE_C_COMPILER        "aarch64-linux-gnu-gcc")
185
+set(CMAKE_CXX_COMPILER      "aarch64-linux-gnu-g++")
186
+set(RUST_COMPILER_TARGET    "aarch64-unknown-linux-gnu")
187
+
188
+# Project Variables needed to cross compile
189
+set(HAVE_ATTRIB_ALIGNED     1)
190
+set(HAVE_ATTRIB_PACKED      1)
191
+set(HAVE_UNAME_SYSCALL      1)
192
+set(HAVE_SAR                1)
193
+set(HAVE_FD_PASSING         1)
194
+set(MMAP_FOR_CROSSCOMPILING ON)
195
+set(ENABLE_SYSTEMD          OFF)
196
+
197
+set( test_run_result
198
+     "PLEASE_FILL_OUT-FAILED_TO_RUN"
199
+     CACHE STRING "Result from try_run" FORCE)
200
+
201
+set( test_run_result__TRYRUN_OUTPUT
202
+     "PLEASE_FILL_OUT-NOTFOUND"
203
+     CACHE STRING "Output from try_run" FORCE)
204
+
205
+#
206
+# Dependencies
207
+#
208
+
209
+set(JSONC_INCLUDE_DIR       "/usr/include/json-c")
210
+set(JSONC_LIBRARY           "/usr/lib/aarch64-linux-gnu/libjson-c.a")
211
+set(ENABLE_JSON_SHARED      OFF)
212
+
213
+set(BZIP2_INCLUDE_DIR       "/usr/include/")
214
+set(BZIP2_LIBRARY           "/usr/lib/aarch64-linux-gnu/libbz2.a")
215
+
216
+set(OPENSSL_ROOT_DIR        "/usr/")
217
+set(OPENSSL_INCLUDE_DIR     "/usr/include/")
218
+set(OPENSSL_CRYPTO_LIBRARY  "/usr/lib/aarch64-linux-gnu/libcrypto.so")
219
+set(OPENSSL_SSL_LIBRARY     "/usr/lib/aarch64-linux-gnu/libssl.so")
220
+
221
+set(LIBXML2_INCLUDE_DIR     "/usr/include/libxml2")
222
+set(LIBXML2_LIBRARY         "/usr/lib/aarch64-linux-gnu/libxml2.so")
223
+
224
+set(PCRE2_INCLUDE_DIR       "/usr/include/")
225
+set(PCRE2_LIBRARY           "/usr/lib/aarch64-linux-gnu/libpcre2-8.so")
226
+
227
+set(CURSES_INCLUDE_DIR      "/usr/include/")
228
+set(CURSES_LIBRARY          "/usr/lib/aarch64-linux-gnu/libncurses.a;/usr/lib/aarch64-linux-gnu/libtinfo.a")
229
+# Tip: You may not need to also link with libtinfo.a, depending on what your distribution provides:
230
+#set(CURSES_LIBRARY          "/usr/lib/aarch64-linux-gnu/libncurses.a")
231
+# Tip: Alternatively, you could link with the shared library:
232
+#set(CURSES_LIBRARY          "/usr/lib/aarch64-linux-gnu/libncurses.so")
233
+
234
+set(ZLIB_INCLUDE_DIR        "/usr/include/")
235
+set(ZLIB_LIBRARY            "/usr/lib/aarch64-linux-gnu/libz.so")
236
+
237
+set(LIBCHECK_INCLUDE_DIR    "/usr/include/")
238
+set(LIBCHECK_LIBRARY        "/usr/lib/aarch64-linux-gnu/libcheck.a")
239
+```
240
+
241
+## Build ClamAV
242
+
243
+You may need to adjust the paths in the command below to suit your needs.
244
+
245
+You'll definitely need to set `CMAKE_STAGING_PREFIX` to your own path, or maybe remove it (see the note, below).
246
+
247
+You may wish to set `CMAKE_INSTALL_PREFIX` to some directory other than `/usr`
248
+
249
+> _Note_: If using a sysroot and `CMAKE_SYSROOT` is set in your `CMAKE_TOOLCHAIN_ARM64.cmake` file, then the `make install` command will install to that sysroot directory. If you want, you can override it with `CMAKE_STAGING_PREFIX`. After the `make install`, it will be on you to copy the stuff from your staging directory to target system. The instructions below do this, because you may not wish to contaminate your sysroot with output from this build, or because your sysroot may be read-only.
250
+
251
+```bash
252
+mkdir build-arm64 && cd build-arm64
253
+
254
+cmake .. \
255
+    -D CMAKE_TOOLCHAIN_FILE=(pwd)/../CMAKE_TOOLCHAIN_ARM64.cmake \
256
+    -D ENABLE_STATIC_LIB=OFF \
257
+    -D ENABLE_SHARED_LIB=ON \
258
+    -D MAINTAINER_MODE=OFF \
259
+    -D ENABLE_EXAMPLES=OFF \
260
+    -D BYTECODE_RUNTIME=interpreter \
261
+    -D CMAKE_BUILD_TYPE=Release \
262
+    -D CMAKE_INSTALL_PREFIX="/usr" \
263
+    -D CMAKE_STAGING_PREFIX=/home/user/stage/usr
264
+
265
+make
266
+make install
267
+```
268
+
269
+## Verify it built for right platform
270
+
271
+We cannot run the ClamAV unit test suite, because we're cross compiling and can't run the programs we build. But we can do a very small test with the Unix `file` command to see that it built for the right platform. For example:
272
+
273
+```bash
274
+file install/bin/clamscan
275
+```
276
+
277
+Example output:
278
+`install/bin/clamscan: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=289a6b738e7421c5bb09c7ee5fc5bb20bfe98025, for GNU/Linux 3.7.0, with debug_info, not stripped`
279
+
280
+If everything looks good, you can probably copy the install files to your system and run it.
0 281
new file mode 100644
... ...
@@ -0,0 +1,124 @@
0
+# Cross-compiling ClamAV on Windows for ARM64
1
+
2
+These are instructions to cross-compile ClamAV on Windows x64 (`x86_64-pc-windows-msvc`) with GCC for Linux arm64 (`aarch64-pc-windows-msvc`).
3
+
4
+## Install build tools, if missing
5
+
6
+Use the Visual Studio Installer tools to add the ARM64 components. E.g. this stuff:
7
+- MSVC v143 - VS 2022 C++ ARM build tools (Latest)
8
+- MSVC v143 - VS 2022 C++ ARM Spectre-mitigated libs (Latest)
9
+- MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (Latest)
10
+- MSVC v143 - VS 2022 C++ ARM64/ARM64EC Spectre-mitigated libs (Latest)
11
+- C++ ATL for latest v143 build tools (ARM)
12
+- C++ ATL for latest v143 build tools (ARM64/ARM64EC)
13
+- C++ ATL for latest v143 build tools with Spectre-Mitigations (ARM)
14
+- C++ ATL for latest v143 build tools with Spectre-Mitigations (ARM64/ARM64EC)
15
+- C++ MFC for latest v143 build tools (ARM)
16
+- C++ MFC for latest v143 build tools (ARM64/ARM64EC)
17
+- C++ MFC for latest v143 build tools with Spectre-Mitigations (ARM)
18
+- C++ MFC for latest v143 build tools with Spectre-Mitigations (ARM64/ARM64EC)
19
+
20
+Install the Rust toolchains needed to cross-compile to arm64:
21
+
22
+```powershell
23
+rustup target add aarch64-pc-windows-msvc
24
+```
25
+
26
+## Use Mussels to build ARM64 C-based library dependencies
27
+
28
+See the [online documentation regarding building dependencies with Mussels](https://docs.clamav.net/manual/Development/build-installer-packages.html#windows). To build for ARM64, change the commands to build like this:
29
+
30
+```powershell
31
+msl build -t arm64 clamav_deps
32
+```
33
+
34
+Once the build is complete, you'll find the ARM64 compiled libraries under `~\.mussels\install\arm64\`.
35
+
36
+## Create a CMake toolchain file
37
+
38
+A CMake toolchain file specifies some toolchain specific variables.
39
+
40
+`CMAKE_TOOLCHAIN_ARM64.cmake`:
41
+```cmake
42
+# Platform
43
+set(CMAKE_SYSTEM_NAME       Windows)
44
+set(CMAKE_SYSTEM_PROCESSOR  arm64)
45
+set(RUST_COMPILER_TARGET    "aarch64-pc-windows-msvc")
46
+
47
+# Project Variables needed to cross compile
48
+set(HAVE_PRAGMA_PACK        1)
49
+set(HAVE_SAR                1)
50
+set(MMAP_FOR_CROSSCOMPILING OFF)
51
+set(ENABLE_SYSTEMD          OFF)
52
+
53
+set( test_run_result
54
+     "PLEASE_FILL_OUT-FAILED_TO_RUN"
55
+     CACHE STRING "Result from try_run" FORCE)
56
+
57
+set( test_run_result__TRYRUN_OUTPUT
58
+     "PLEASE_FILL_OUT-NOTFOUND"
59
+     CACHE STRING "Output from try_run" FORCE)
60
+```
61
+
62
+## Build ClamAV
63
+
64
+You may need to adjust the paths in the command below to suit your needs.
65
+
66
+```powershell
67
+mkdir build-arm64
68
+cd build-arm64
69
+
70
+cmake .. -G "Visual Studio 17 2022" -A arm64 `
71
+    -D JSONC_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include\\json-c" `
72
+    -D JSONC_LIBRARY="$HOME\\.mussels\\install\\arm64\\lib\\json-c.lib" `
73
+    -D BZIP2_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include" `
74
+    -D BZIP2_LIBRARY_RELEASE="$HOME\\.mussels\\install\\arm64\\lib\\libbz2.lib" `
75
+    -D CURL_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include" `
76
+    -D CURL_LIBRARY="$HOME\\.mussels\\install\\arm64\\lib\\libcurl_imp.lib" `
77
+    -D OPENSSL_ROOT_DIR="$HOME\\.mussels\\install\\arm64\\" `
78
+    -D OPENSSL_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include" `
79
+    -D LIB_EAY_DEBUG="$HOME\\.mussels\\install\\arm64\\lib\\libcrypto.lib" `
80
+    -D SSL_EAY_DEBUG="$HOME\\.mussels\\install\\arm64\\lib\\libssl.lib" `
81
+    -D ZLIB_LIBRARY="$HOME\\.mussels\\install\\arm64\\lib\\libssl.lib" `
82
+    -D LIBXML2_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include\\libxml" `
83
+    -D LIBXML2_LIBRARY="$HOME\\.mussels\\install\\arm64\\lib\\libxml2.lib" `
84
+    -D PCRE2_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include" `
85
+    -D PCRE2_LIBRARY="$HOME\\.mussels\\install\\arm64\\lib\\pcre2-8.lib" `
86
+    -D PDCURSES_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include" `
87
+    -D CURSES_LIBRARY="$HOME\\.mussels\\install\\arm64\\lib\\pdcurses.lib" `
88
+    -D PThreadW32_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include" `
89
+    -D PThreadW32_LIBRARY="$HOME\\.mussels\\install\\arm64\\lib\\pthreadVC3.lib" `
90
+    -D ZLIB_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include" `
91
+    -D ZLIB_LIBRARY="$HOME\\.mussels\\install\\arm64\\lib\\zlibstatic.lib" `
92
+    -D LIBCHECK_INCLUDE_DIR="$HOME\\.mussels\\install\\arm64\\include" `
93
+    -D LIBCHECK_LIBRARY="$HOME\\.mussels\\install\\arm64\\lib\\checkDynamic.lib" `
94
+    -D CMAKE_TOOLCHAIN_FILE=$pwd\\..\\CMAKE_TOOLCHAIN_ARM64.cmake `
95
+    -D ENABLE_STATIC_LIB=OFF `
96
+    -D ENABLE_SHARED_LIB=ON `
97
+    -D MAINTAINER_MODE=OFF `
98
+    -D ENABLE_EXAMPLES=OFF `
99
+    -D BYTECODE_RUNTIME=interpreter `
100
+    -D HAVE_PRAGMA_PACK=1 `
101
+    -D HAVE_SAR=1 `
102
+    -D CMAKE_INSTALL_PREFIX="install"
103
+
104
+cmake --build . --config Release --target install
105
+```
106
+
107
+## Verify it built for right platform
108
+
109
+We cannot run the ClamAV unit test suite, because we're cross compiling and can't run the programs we build. But we can do a very small test to see that it built for the right platform.
110
+
111
+Pop into WSL2 (Windows Subsystem for Linux 2) to make use of the `file` utility:
112
+
113
+```powershell
114
+❯ wsl
115
+Welcome to fish, the friendly interactive shell
116
+Type `help` for instructions on how to use fish
117
+
118
+clamav-micah-2/build-arm64 on  main [$] via C v9.4.0-gcc via △ v3.27.2
119
+❯ file install/clamscan.exe
120
+install/clamscan.exe: PE32+ executable (console) Aarch64, for MS Windows
121
+```
122
+
123
+If everything looks good, you can probably copy the install files to your system and run it.
... ...
@@ -782,6 +782,10 @@ Run `rustup target add --help` for help.
782 782
 For a list of available target triples, see:
783 783
 https://doc.rust-lang.org/nightly/rustc/platform-support.html
784 784
 
785
+Step-by-step instructions for cross-compiling ClamAV:
786
+- [Linux GCC amd64 to arm64](./INSTALL-cross-linux-arm64.md)
787
+- [Windows MSVC x64 to arm64](./INSTALL-cross-windows-arm64.md)
788
+
785 789
 ## Un-install
786 790
 
787 791
 CMake doesn't provide a simple command to uninstall. However, CMake does build