交叉编译n2n,以openwrt为例子
预备知识
1 什么是交叉编译?
1.1 本地编译
简单粗暴的解释一下,在当前架构的pc下,直接由编译工具编译生成的程序或者是库文件,可以直接在当前的环境运行。这样的编译,可以叫做本地编译。在当前架构/平台下编译出来的程序,只能在当前架构/平台下运行。
1.2 交叉编译
交叉编译是一个相对的概念,就是在一种架构/平台下编译出来的程序或是库文件,放到别的架构/平台上运行。目标执行该程序的架构和环境不一样,属于交叉的编译。
交叉编译是做嵌入是开发的基本概念。
1.3 例子
就拿n2n来说,开发者提供了源码给我们,想要在各个平台上运行该程序,就需要交叉编译出不同目标平台/架构的应用程序,才能保证程序可以运行。
2 为什么需要交叉编译?
嵌入式系统中的资源太少!!
具体的解释就是:交叉编译出来的程序,所要运行的目标环境中,各种资源,都相对有限,所以很难进行直接的本地编译。
3 常见的平台,并非所有的
darwin_amd64
freebsd_386
freebsd_amd64
linux_386
linux_amd64
linux_arm
linux_arm64
linux_mips
linux_mips64
linux_mips64le
linux_mipsle
windows_386
windows_amd64
简单解释一下:amd64,说的就是64位的机器,386,说的是32位的机器。至于其他i686,x86等,大家可以自行搜索相关的关键字,了解一下,这里不做阐述了。
至于前缀,一目了然,不做说明。
4 还需要了解的基本概念
这个文档针对的是n2n但不限于其他知识的了解,简单的描述一下linux相关的基本概念。
4.1 linux用户
Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统。
管理员用户:root,拥有最高的权限。
当你登录了linux的时候,绝大多数机器默认使用的是bash交互环境,可以通过提示符区分用户。
root@soul-PC:~#
注意到上面的那一行,root便是只的是你当前用户,@后面的是主机,~表示的是当前用户[root]的家目录,通常是/root。最后的#号是最容易区分的,一般#号标示的就是root用户。
下面看看普通用户:
soul@soul-PC:~$
$ 符号,通常标示的是普通用户,
在绝大多数的情况下,我们用到的都是普通用户,一般机器登录也是普通用户。
在以后的编译过程中,我用的都是普通用户做演示。
当然,当你需要用到超级用户权限的时候,有很多的方式可以获得管理员权限。你可以装sudo软件包,这样,需要管理员权限的时候,只需要在命令前面加上sudo就可以了。
soul@soul-PC:~$ sudo ifconfig
4.2 环境变量
还是简单的介绍一下吧。
我们为什么可以使用Linux的命令,是因为linux系统的命令所在的路径,基本上行都是设置了环境变量。
注意:每个用的的环境变量可能不是一样的,环境变量可以全局配置,也可以某个用户自己配置自己的。
一般个人的linux‘系统,不需要做全局环境变量的配置。只需要在当前用户的家目录下修改配置文件就可以了。
我个人习惯是配置在.bashrc文件里配置。
soul@soul-PC:~$ pwd
/home/soul
soul@soul-PC:~$ ls -al .bashrc
-rw-r--r-- 1 soul soul 3822 6月 4 2018 .bashrc
我们可以用下面的命令来查看当然用户的环境变量:
soul@soul-PC:~$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/sbin
看到我在soul用户下的环境变量路径有这些,意味着,在这个路径下的所有可以执行的文件,我都可以在任何地方使用他,比如ls 命令。
再说一下,一个命令它是放在哪里,它是什么,我怎么知道他?跟我做。举个例子,一ls命令为例子:
soul@soul-PC:~$ which ls #我要看ls在那个路径下
/bin/ls
soul@soul-PC:~$ whereis ls #我要看路径等其他的
ls: /bin/ls /usr/share/man/man1/ls.1.gz
soul@soul-PC:~$ type ls #我要看ls是什么类型的命令
ls 是 `ls --color=auto' 的别名
/bin/ 目录下,包含了我们常用的命令。就简单介绍到这里吧。环境变量的配置,后面会讲。
准备工作
要编译,就现在搭建环境,当然,你也得会一些常用的linux操作命令,基本常识。
一台linux机器(苹果也可以),虚拟机装linux也可以。
我的linux机子如下:
~$ uname -a
Linux soul-PC 4.15.0-21deepin-generic #21 SMP Mon May 21 05:20:09 UTC 2018 x86_64 GNU/Linux
OpenSSL 一会用的到
下载地址:http://distfiles.macports.org/openssl/
Openwrt 的 SDK 或 toolchain
首先你的知道openwrt的下载的官网,http://downloads.openwrt.org/,进入后你会看到各个版本和分支。这里我以Chaos Calmer 15.05.1为例子,我手里有一个联发科板子。
找到你对应的型号芯片
具体的芯片
进去里面有很多该芯片的各类固件!你不刷机,不要管。
找到sdk
我们只需要下载sdk开发工具就可以了!
下载以后解压出来,解压命令自己学习一下就行了。
注意,新的压缩包为了减小体积,是两层压缩,xz,结尾,tar结尾。所以你得解压两次。
soul@soul-PC:~/Downloads$ tar -jxvf OpenWrt-SDK-15.05.1-ramips-mt7688_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64.tar.bz2
更改一下sdk的名字,路径太长,如果有报错,不便于分析。
soul@soul-PC:~/Downloads$ mv OpenWrt-SDK-15.05.1-ramips-mt7688_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64 sdk
接着把sdk复制到你偏爱的目录。
找到sdk的gcc工具目录
soul@soul-PC:~/op/sdk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin$ ls
c_rehash mipsel-openwrt-linux-strip
g++-uc mipsel-openwrt-linux-uclibc-addr2line
g++-uc+std mipsel-openwrt-linux-uclibc-ar
ldd mipsel-openwrt-linux-uclibc-as
mipsel-openwrt-linux-addr2line mipsel-openwrt-linux-uclibc-c++
mipsel-openwrt-linux-ar mipsel-openwrt-linux-uclibc-c++filt
mipsel-openwrt-linux-as mipsel-openwrt-linux-uclibc-cpp
mipsel-openwrt-linux-c++ mipsel-openwrt-linux-uclibc-elfedit
mipsel-openwrt-linux-c++filt mipsel-openwrt-linux-uclibc-g++
mipsel-openwrt-linux-cpp mipsel-openwrt-linux-uclibc-gcc
mipsel-openwrt-linux-elfedit mipsel-openwrt-linux-uclibc-gcc-4.8.3
mipsel-openwrt-linux-g++ mipsel-openwrt-linux-uclibc-gcc-ar
mipsel-openwrt-linux-gcc mipsel-openwrt-linux-uclibc-gcc-nm
mipsel-openwrt-linux-gcc-4.8.3 mipsel-openwrt-linux-uclibc-gcc-ranlib
mipsel-openwrt-linux-gcc-ar mipsel-openwrt-linux-uclibc-gcov
mipsel-openwrt-linux-gcc-nm mipsel-openwrt-linux-uclibc-gdb
mipsel-openwrt-linux-gcc-ranlib mipsel-openwrt-linux-uclibc-gprof
mipsel-openwrt-linux-gcov mipsel-openwrt-linux-uclibc-ld
mipsel-openwrt-linux-gdb mipsel-openwrt-linux-uclibc-ld.bfd
mipsel-openwrt-linux-gprof mipsel-openwrt-linux-uclibc-nm
mipsel-openwrt-linux-ld mipsel-openwrt-linux-uclibc-objcopy
mipsel-openwrt-linux-ld.bfd mipsel-openwrt-linux-uclibc-objdump
mipsel-openwrt-linux-nm mipsel-openwrt-linux-uclibc-ranlib
mipsel-openwrt-linux-objcopy mipsel-openwrt-linux-uclibc-readelf
mipsel-openwrt-linux-objdump mipsel-openwrt-linux-uclibc-size
mipsel-openwrt-linux-ranlib mipsel-openwrt-linux-uclibc-strings
mipsel-openwrt-linux-readelf mipsel-openwrt-linux-uclibc-strip
mipsel-openwrt-linux-size openssl
mipsel-openwrt-linux-strings
接着添加环境比变量
soul@soul-PC:~/op/sdk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin$ pwd
/home/soul/op/sdk/staging_dir/toolchain-mipsel_24kc_gcc-7.3.0_musl/bin
soul@soul-PC:~/op/sdk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin$ gedit ~/.bashrc
在最后加上
export PATH=$PATH:/home/soul/op/sdk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin
export STAGING_DIR=/home/soul/op/sdk/staging_dir
保存,退出
接着让配置文件生效,这样做:
soul@soul-PC:~/op/sdk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin$ source ~/.bashrc
soul@soul-PC:~/op/sdk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/sbin:/home/soul/op/sdk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin
看到我们添加的环境变量已经生效了。此时你就可以在任何地方使用你的工具了。
在命令行敲mips[tab],应该能自动补全你的命令了。
接着编译一个简单的是程序,helloworld
#include <stdio.h>
int main(int argc,char* argv[])
{
puts("Hello World!");
return 0;
}
soul@soul-PC:~/op/c$ mipsel-openwrt-linux-gcc -o hello hello.c
soul@soul-PC:~/op/c$ ls
hello hello.c
soul@soul-PC:~/op/c$ ./hello
bash: ./hello: cannot execute binary file: Exec format error
soul@soul-PC:~/op/c$
尝试在本机上执行文件,报错。不是可执行文件,那当然,这是在目标平台执行的文件,此时把文件放到你的目标机器上执行,就可以输出helloworld啦。
到此,基本环境已经搭建测试成功了。
交叉编译OpenSSL
下载源码,解压
下载地址:http://distfiles.macports.org/openssl/
soul@soul-PC:~/Downloads$ tar -zxvf openssl-1.0.2q.tar.gz
进入openssl目录,设置生成路径,不需要生成汇编
soul@soul-PC:~/op/openssl-1.0.2q$ ./config no-asm shared --prefix=/home/soul/op/sdk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2
接着修改 MakeFile 文件 ,指定交叉编译的gcc
...
CC= mipsel-openwrt-linux-gcc
...
AR= mipsel-openwrt-linux-ar $(ARFLAGS) r
RANLIB= mipsel-openwrt-linux-ranlib
...
NM= mipsel-openwrt-linux-nm
...
MAKEDEPPROG= mipsel-openwrt-linux-gcc
同时,删除-m64,两个地方需要删除。
之后编译,最后,安装,编译时间看机器性能了。
soul@soul-PC:~/op/openssl-1.0.2q$ make
安装:
soul@soul-PC:~/op/openssl-1.0.2q$ make install
到此,openssl,编译结束
交叉编译n2n
好的 接下来我们下载源码:
~$ git clone https://github.com/meyerd/n2n.git
之后你就看到n2n的目录了。进去目录,看了下,可以使用cmake构建编译工程,我这里直接使用makefile编译,不使用cmake。
~$ cd n2n/n2n_v2/
~/n2n/n2n_v2(master)$ ls
benchmark.c gen_keyfile.py n2n.c n2n_wire.h supernode.1 twofish.c
benchmark_hashtable.c HACKING n2n.h NEW_FEATURES.txt transform_aes.c twofish.h
cmake/ INSTALL n2n_keyfile.c openwrt/ transform_null.c unix-scm.c
CMakeLists.txt lzoconf.h n2n_keyfile.h README transform_tf.c version.c
COPYING lzodefs.h n2n.spec scm.h tuntap_freebsd.c win32/
debian/ minilzo.c n2n_test.c scripts/ tuntap_linux.c wire.c
edge.8 minilzo.h n2n_transforms.h sglib.h tuntap_netbsd.c wireshark/
edge.c munin/ n2n_v2.7 sn.c tuntap_osx.c
~/n2n/n2n_v2(master)$
打开n2n工程目录,创建或者复制Makefile文件。
注意文件内容指定了“Makefile”,所以你创建文件的时候,名字也得大写M开头。
N2N_VERSION=2.1.0
N2N_OSNAME=$(shell uname -p)
########
CC= mipsel-openwrt-linux-gcc
DEBUG?=-g3
#OPTIMIZATION?=-O2
WARN?=-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs
#Ultrasparc64 users experiencing SIGBUS should try the following gcc options
#(thanks to Robert Gibbon)
PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs
N2N_DEFINES=
N2N_OBJS_OPT=
LIBS_EDGE_OPT=
N2N_OPTION_AES?="yes"
#N2N_OPTION_AES=no
ifeq ($(N2N_OPTION_AES), "yes")
N2N_DEFINES+="-DN2N_HAVE_AES"
LIBS_EDGE_OPT+=-lcrypto
endif
CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN) $(OPTIONS) $(PLATOPTS) $(N2N_DEFINES)
INSTALL=install
MKDIR=mkdir -p
INSTALL_PROG=$(INSTALL) -m755
INSTALL_DOC=$(INSTALL) -m644
# DESTDIR set in debian make system
PREFIX?=$(DESTDIR)/usr
#BINDIR=$(PREFIX)/bin
SBINDIR=$(PREFIX)/sbin
MANDIR?=$(PREFIX)/share/man
MAN1DIR=$(MANDIR)/man1
MAN7DIR=$(MANDIR)/man7
MAN8DIR=$(MANDIR)/man8
N2N_LIB=n2n.a
N2N_OBJS=n2n.o n2n_keyfile.o wire.o minilzo.o twofish.o \
transform_null.o transform_tf.o transform_aes.o \
tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o tuntap_osx.o version.o unix-scm.o
LIBS_EDGE+=$(LIBS_EDGE_OPT)
LIBS_SN=
#For OpenSolaris (Solaris too?)
ifeq ($(shell uname), SunOS)
LIBS_EDGE+=-lsocket -lnsl
LIBS_SN+=-lsocket -lnsl
endif
APPS=edge
APPS+=supernode
DOCS=edge.8.gz supernode.1.gz n2n_v2.7.gz
all: $(APPS) $(DOCS)
edge: edge.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
$(CC) $(CFLAGS) edge.c $(N2N_LIB) $(LIBS_EDGE) -o edge
test: test.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
$(CC) $(CFLAGS) test.c $(N2N_LIB) $(LIBS_EDGE) -o test
supernode: sn.c $(N2N_LIB) n2n.h Makefile
$(CC) $(CFLAGS) sn.c $(N2N_LIB) $(LIBS_SN) -o supernode
benchmark: benchmark.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
$(CC) $(CFLAGS) benchmark.c $(N2N_LIB) $(LIBS_SN) -o benchmark
.c.o: n2n.h n2n_keyfile.h n2n_transforms.h n2n_wire.h twofish.h Makefile
$(CC) $(CFLAGS) -c $<
%.gz : %
gzip -c $< > $@
$(N2N_LIB): $(N2N_OBJS)
ar rcs $(N2N_LIB) $(N2N_OBJS)
# $(RANLIB) $@
version.o: Makefile
$(CC) $(CFLAGS) -DN2N_VERSION='"$(N2N_VERSION)"' -DN2N_OSNAME='"$(N2N_OSNAME)"' -c version.c
clean:
rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) test *.dSYM *~
install: edge supernode edge.8.gz supernode.1.gz n2n_v2.7.gz
echo "MANDIR=$(MANDIR)"
$(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR)
$(INSTALL_PROG) supernode $(SBINDIR)/
$(INSTALL_PROG) edge $(SBINDIR)/
$(INSTALL_DOC) edge.8.gz $(MAN8DIR)/
$(INSTALL_DOC) supernode.1.gz $(MAN1DIR)/
$(INSTALL_DOC) n2n_v2.7.gz $(MAN7DIR)/
至此,编译结束,看下生成的文件。
soul@soul-PC:~/n2n/n2n_v2$ ls
CMakeLists.txt edge.8 n2n.h scm.h transform_tf.o unix-scm.c
COPYING edge.8.gz n2n.o scripts tuntap_freebsd.c unix-scm.o
HACKING edge.c n2n.spec sglib.h tuntap_freebsd.o version.c
INSTALL gen_keyfile.py n2n_keyfile.c sn.c tuntap_linux.c version.o
Makefile lzoconf.h n2n_keyfile.h supernode tuntap_linux.o win32
NEW_FEATURES.txt lzodefs.h n2n_keyfile.o supernode.1 tuntap_netbsd.c wire.c
README minilzo.c n2n_test.c supernode.1.gz tuntap_netbsd.o wire.o
benchmark.c minilzo.h n2n_transforms.h transform_aes.c tuntap_osx.c wireshark
benchmark_hashtable.c minilzo.o n2n_v2.7 transform_aes.o tuntap_osx.o
cmake munin n2n_v2.7.gz transform_null.c twofish.c
debian n2n.a n2n_wire.h transform_null.o twofish.h
edge n2n.c openwrt transform_tf.c twofish.o
看了下edge,supmode文件,还是有点大,怎么办?可以soul@soul-PC:~/n2n/n2n_v2$ mipsel-openwrt-linux-strip edge supernode一下,稍微减小了一些体积。
在Makefile文件可以适当的参考gcc工具的用法,编译输出选项,调整后,体积也适当减小,这里不做阐述了。
未完,待更新。有建议或者意见留言评论。
新版n2n已经更新集成了openwrt的makefile了,放进去sdk里make就OK了
请问有编译好的新版的n2n V2.4吗?可以用于LEDE的
是的,现在简单一些了,但前提是你要有SD卡、USB之类的存储空间来放sdk。
楼上的,目前没有lede的,需要自己编译。万一有了,我会放到这里去。
supernode.ml