|
| 1 | +# OpenWRT 编译环境搭建 |
| 2 | + |
| 3 | +#### 首先 配置编译环境,安装需要用的依赖 |
| 4 | + |
| 5 | + sudo apt-get install asciidoc bash bc binutils bzip2 fastjar g++ gcc util-linux libgtk2.0-dev intltool jikespg make genisoimage patch perl-modules python2.7-dev rsync ruby sdcc wget gettext zlib1g-dev libboost1.55-tools-dev libusb-dev bin86 bcc sharutils openjdk-7-jdk build-essential subversion git-core libncurses5-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip |
| 6 | +#### 然后 同步源代码 |
| 7 | + |
| 8 | + svn co svn://svn.openwrt.org/openwrt/trunk/ |
| 9 | + |
| 10 | +#### 然后更新和安装feeds(可能需要VPN) |
| 11 | + |
| 12 | + cd trunk/ |
| 13 | + ./scripts/feeds update -a |
| 14 | + ./scripts/feeds install -a |
| 15 | + |
| 16 | +#### 编译环境搭建完成 接下来是检查配置环境 |
| 17 | + |
| 18 | +必须使用非root用户进行操作,添加一个普通用户。(注意:如果使用root进行操作的话,会提示检查失败:Checking 'non-root'... failed.) |
| 19 | + |
| 20 | + # adduser openwrt |
| 21 | + # su openwrt |
| 22 | + |
| 23 | +为了防止文件读写权限造成问题,需要将源码copy到openwet的根目录下进行所有操作。 |
| 24 | + |
| 25 | + $ cd ~ |
| 26 | + $ cp -r /path/to/openwrt/trunk ./ |
| 27 | + $ cd trunk/ |
| 28 | + |
| 29 | +3.下载feeds |
| 30 | + |
| 31 | +Feeds是OpenWrt环境所需要的软件包套件。最重要的feeds有: |
| 32 | + |
| 33 | +‘packages’一些额外的基础路由器特性软件 |
| 34 | + |
| 35 | +‘LuCI’OpenWrt默认的GUI |
| 36 | + |
| 37 | +‘Xwrt’另一种可选的GUI界面 |
| 38 | + |
| 39 | +需要能够连接互联网。 |
| 40 | + |
| 41 | +在下载之前可以通过查看’feeds.conf.default’文件,来检查哪些文件需要包含在环境中。 |
| 42 | + |
| 43 | +开始下载,使用: |
| 44 | + |
| 45 | +[openwrt@localhost trunk]$ ./scripts/feeds update -a |
| 46 | + |
| 47 | +安装feeds包,只有安装之后,在后面的make menuconfig时,才可以对相关配置进行勾选。 |
| 48 | + |
| 49 | +[openwrt@localhost trunk]$ ./scripts/feeds install -a |
| 50 | + |
| 51 | +如果更新了feeds的配置文件,需要添加新的软件包用于生成系统。只需进行重复操作: |
| 52 | + |
| 53 | +[openwrt@localhost trunk]$ ./scripts/feeds update -a |
| 54 | + |
| 55 | +[openwrt@localhost trunk]$ ./scripts/feeds install -a |
| 56 | + |
| 57 | + |
| 58 | + 4.进行配置 |
| 59 | + |
| 60 | +编译过程使用的交叉编译,交叉编译生成的SDK以及image等文件的类型取决于开发环境、应用硬件、以及源码版本。所以要对自己的环境进行了解,才能进行正确的配置。我在配置过程中,就遇到了这个问题,我的硬件是brcm47xx,在第一次编译的时候,选择地是Target System (Broadcom BCM947xx/953xx),最后生成的包无法在router上安装,版本不匹配。第二次安装时,选择了Target System (Broadcom BCM947xx/953xx[2.4]),安装成功,我的板子可能只支持linux2.4的内核。(设备型号是Linksys Wrt54gs v3.0) (2011.05.01添加:其实Linksys Wrt54gs v3.0是支持Linux 2.6版本的,Target System 选择 Broadcom BCM947xx/953xx,编译后也是可以用的,这周末由于项目需要改某个软件,每次修改代码后,都得重新编译一下固件,经过来回编译了十来次,都可以使用。另外。内核版本升级之后,无线驱动改成了mac802.11,而非以前的wl,以为wl.o这个专门的库只在linux2.4中才用到。) |
| 61 | + |
| 62 | +[openwrt@localhost trunk]$ make defconfig |
| 63 | + |
| 64 | +[openwrt@localhost trunk]$ make prereq |
| 65 | + |
| 66 | +[openwrt@localhost trunk]$ make menuconfig |
| 67 | + |
| 68 | +通过文本对话框进行选项配置,最主要的配置项有: |
| 69 | + |
| 70 | +Target system(目标系统类型) |
| 71 | + |
| 72 | +Package selection(软件包选择) |
| 73 | + |
| 74 | +Build system settings (编译系统设置) |
| 75 | + |
| 76 | +Kernel modules (内核模块) |
| 77 | + |
| 78 | +[*]表示:这个包裹选中编译,并安装在firmware中; |
| 79 | + |
| 80 | +[M]表示:这个软件包选中编译,但并不安装在firmware中。 |
| 81 | + |
| 82 | +在退出Menuconfig的时,会提示是否保存配置。 |
| 83 | + |
| 84 | +在此我只对target system进行了选择;勾选了Advanced configuration option和Build the OpenWrt SDK选项。 |
| 85 | + |
| 86 | +5. 编译 |
| 87 | + |
| 88 | +(1)一般情况,使用一个简单的命令: |
| 89 | + |
| 90 | +[openwrt@localhost trunk]$ make |
| 91 | + |
| 92 | +(2)在多核处理器系统上为提高速度,可使用(例如用3核处理器): |
| 93 | + |
| 94 | +[openwrt@localhost trunk]$ make –j 3 |
| 95 | + |
| 96 | +(3)在后台进行编译,使用空闲的I/O资源和CPU性能,可使用(例如使用双核处理器) |
| 97 | + |
| 98 | +[openwrt@localhost trunk]$ onice -c 3 nice -n 20 make -j 2 |
| 99 | + |
| 100 | +(4)编译一个单独的软件包(例如在cups软件包): |
| 101 | + |
| 102 | +[openwrt@localhost trunk]$ make package/cups/compile V=99 |
| 103 | + |
| 104 | +(5)如果特殊原因需要分析编译报错信息: |
| 105 | + |
| 106 | +[openwrt@localhost trunk]$ make V=99 2>&1 |tee build.log |grep -i error |
| 107 | + |
| 108 | +说明:将编译的所有输出信息保存在build.log中,将error信息打印在屏幕上。 |
| 109 | + |
| 110 | +(6)一个复杂指令的应用 |
| 111 | + |
| 112 | +[openwrt@localhost trunk]$ ionice -c 3 nice -n 20 make -j 2 V=99 CONFIG_DEBUG_SECTION_MISMATCH=y 2>&1 \|tee build.log |egrep -i '(warn|error)' |
| 113 | + |
| 114 | +说明:将编译的所有输出信息保存在build.log中,将error和warning信息打印在屏幕上。编译过程使用双核CPU,占用后台资源。 |
| 115 | + |
| 116 | + |
| 117 | +6.生成镜像(Image)位置 |
| 118 | + |
| 119 | +新生成的镜像会默认放在新建的一个bin目录下。例如:/bin/brcm-2.4/packages |
| 120 | + |
| 121 | +[openwrt@localhost trunk]$ ls bin/* |
| 122 | + |
| 123 | +将编译好的镜像做个备份,例如备份到/目录下: |
| 124 | + |
| 125 | +[openwrt@localhost trunk]$ cp bin / |
| 126 | + |
| 127 | + |
| 128 | +7.清理工作 |
| 129 | + |
| 130 | +建议现在清理编译产生的文件,以免下次编译时造成冲突,(文件如果存在的话,将不会被替换),执行make clean |
| 131 | + |
| 132 | +注意:在执行clean命令,确保已经将编译好的image进行了备份。清理工作会清楚bin目录。 |
| 133 | + |
| 134 | +[openwrt@localhost trunk]$ make clean |
| 135 | + |
| 136 | +除了清除生成的目录,还想清除交叉编译工具(以及工具链目录) |
| 137 | + |
| 138 | +[openwrt@localhost trunk]$ make dirclean |
| 139 | + |
| 140 | +清除所有相关的东西,包括下载的软件包,配置文件,feed内容等:(不建议使用) |
| 141 | + |
| 142 | +[openwrt@localhost trunk]$ make distclean |
| 143 | + |
| 144 | +对于更新feeds后出现的错误: |
| 145 | + |
| 146 | +ERROR:please fix package/feeds/packages/mc/Makefile 等类似的问题,需要执行这条语句进行系统的清理 |
| 147 | + |
| 148 | + |
| 149 | +更详细的信息建议您参考 |
| 150 | +http://downloads.openwrt.org/kamikaze/docs/openwrt.html |
| 151 | +应该是当前最新最权威的文档 |
| 152 | + |
| 153 | + |
| 154 | + |
| 155 | +编译过程中需要通过官网下载很多相关的软件包,所以必须保证能够顺利连上外网。由于下载速度的限制,编译过程大概需要数小时。编译结束后,所有的产品都会放在编译根目录下的bin/yourtarget/. 例如:我所编译的产物都放在./bin/brcm47xx/下,其中文件主要有几类: |
| 156 | +(1). bin/.trx 文件: 这些都是在我们所选的target-system的类别之下,针对不同路由器型号、版本编译的路由器固件。这些不同路由器的型号和版本是openwrt预先设置好的,我们不需要更改。至于.bin和.trx的区别,一种说法是,第一次刷路由器的时候,需要用.bin文件,如果需要再升级,则不能再使用. bin文件,而需要用.trx文件。原因是,.bin是将路由器的相关配置信息和.trx封装在一起而生成的封包,也就是说是包含路由器版本信息的. trx。在第一次刷固件的时候,我们需要提供这样的信息,而在后续升级时,则不再需要,用.trx文件即可。 |
| 157 | +(2)packages文件夹: 里面包含了我们在配置文件里设定的所有编译好的软件包。默认情况下,会有默认选择的软件包。 |
| 158 | +(3) OpenWrt-SDK.**.tar.bz2: 这个也就是我们定制编译好的OpenWRT SDK环境。我们将用这个来进行OpenWrt软件包的开发。例如,我所编译好的SDK环境包为:/bin/brcm47xx/OpenWrt-SDK- brcm47xx-for-Linux-x86_64-gcc-4.3.3+cs_uClibc-0.9.30.1.tar.bz2 |
| 159 | +可以从名称上看出,target system是brcm47xx,host system是Linux-x86_64,使用的编译工具以及库是4.3.3+cs_uClibc-0.9.30.1。 |
| 160 | +(4)md5sums 文件: 这个文件记录了所有我们编译好的文件的MD5值,来保证文件的完整性。因为文件的不完整,很容易将路由器变成“砖头”。 |
| 161 | +需要主要的是,编译完成后,一定要将编译好的bin目录进行备份(如果里面东西对你很重要的话),因为在下次编译之前,执行make clean 会将bin目录下的所有文件给清除掉!! |
| 162 | +2、 更改原有packages |
| 163 | +在编译根目录下会有一个dl的目录,这个目录其实是“download”的简写,在编译前期,需要从网络下载的数据包都会放在这个目录下,这些软件包的一个特点就是,会自动安装在所编译的固件中,也就是我们make menuconfig的时候,为固件配置的一些软件包。如果我们需要更改这些源码包,只需要将更改好的源码包打包成相同的名字放在这个目录下,然后开始编译即可。编译时,会将软件包解压到build_dir目录下。 |
| 164 | +当然,你也可以自己在dl里面创建自己的软件包,然后更改相关的配置文件,让openwrt可以识别这个文件包。 |
| 165 | +由于我的项目更改的内容是底层的,需要跟固件一起安装。所以,我使用的方法就是直接更改dl目录下软件包,然后重新进行固件编译。感觉类似于Linux的内核编译。反复编过十多次,没有任何问题。 |
| 166 | + |
| 167 | + |
| 168 | +第一次编译由于要下载大量的软件包,慢慢的等吧,快则半小时,慢则2,3小时. 如果下载过慢,建议您中断编译过程,然后用迅雷去主动下载,放到./dl目录下。一个加快速度的小技巧: 本站小编已经将将一些常用的软件包打包成dl.tar,放在http://ul.to/2y8a2w, 下载后用tar xvf dl.tar(在windows下用winrar打开即可,然后你用ftp或者samba之类传到Linux PC上),将解包出来的东东直接放到./dl目录下,相必会大大加快初次安装、编译的速度。同样在http://ul.to/fasgus上可下载linux-2.36.30.10.tar.bz2,当然您也可以用迅雷之类的工具来下。 |
| 169 | +8. 编译好的文件在当前目录的bin文件夹下。 |
| 170 | +如果是brcm-2.4 |
| 171 | +ls bin/brcm-2.4/ |
| 172 | +就可以看到很多熟悉的文件了。 |
| 173 | + |
| 174 | +9、 安装OpenWrt |
| 175 | + |
| 176 | +找到对应的固件,进行固件升级。网上方法很多,这里不再赘述。 |
| 177 | + |
| 178 | + |
| 179 | + |
| 180 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| 181 | + |
| 182 | +下面我们编写自己的package: |
| 183 | + |
| 184 | +新建自己的packages |
| 185 | +对于自己新建的package,而这个package又不需要随固件一起安装,换句话说,就是可以当做一个可选软件包的话。我们可以利用我们的SDK环境来单独编译,编译后会生成一个ipk的文件包。然后利用 opkg install xxx.ipk 来安装这个软件。 |
| 186 | +下面具体说下,如何编译一个helloword的软件包。 |
| 187 | +(1)首先,编写helloworld程序 |
| 188 | +编写helloworld.c |
| 189 | +/**************** |
| 190 | +* Helloworld.c |
| 191 | +* The most simplistic C program ever written. |
| 192 | +* An epileptic monkey on crack could write this code. |
| 193 | +*****************/ |
| 194 | +#include <stdio.h> |
| 195 | +#include <unistd.h> |
| 196 | +int main(void) |
| 197 | +{ |
| 198 | +printf("Hell! O' world, why won't my code compile?\n\n"); |
| 199 | +return 0; |
| 200 | +} |
| 201 | +编写Makefile文件 |
| 202 | +# build helloworld executable when user executes "make" |
| 203 | +helloworld: helloworld.o |
| 204 | +$(CC) $(LDFLAGS) helloworld.o -o helloworld |
| 205 | +helloworld.o: helloworld.c |
| 206 | +$(CC) $(CFLAGS) -c helloworld.c |
| 207 | +# remove object files and executable when user executes "make clean" |
| 208 | +clean: |
| 209 | +rm *.o helloworld |
| 210 | + |
| 211 | +在这两个文件的目录下,执行make 应该可以生成helloworld的可执行文件。执行helloworld后,能够打印出“Hell! O' world, why won't my code compile?”。这一步,主要保证我们的源程序是可以正常编译的。下面我们将其移植到OpenWRT上。 |
| 212 | +(2)将OpenWrt-SDK-brcm47xx-for-Linux-x86_64-gcc-4.3.3+cs_uClibc-0.9.30.1.tar.bz2解压 |
| 213 | +tar –xvf OpenWrt-SDK-brcm47xx-for-Linux-x86_64-gcc-4.3.3+cs_uClibc-0.9.30.1.tar.bz2 |
| 214 | +(3)进入SDK |
| 215 | +cd OpenWrt-SDK-brcm47xx-for-Linux-x86_64-gcc-4.3.3+cs_uClibc-0.9.30.1 |
| 216 | +可以看到里面的目录结构跟我们之前source的目录结构基本相同,所需要编译的软件包,需要放置在package目录下 |
| 217 | +(4)在package目录下创建helloworld目录 |
| 218 | +cd package |
| 219 | +mkdir helloworld |
| 220 | +cd helloworld |
| 221 | +(5)创建src目录,拷贝 helloworld文件 |
| 222 | +mkdir src |
| 223 | +cp /home/wrt/test/helloworld.c src |
| 224 | +cp /home/wrt/test/Makefile src |
| 225 | +(6)在helloworld目录下创建Makefile文件 |
| 226 | +这个Makefile文件是给OpenWRT读的,而之前写的那个Makefile文件是针对helloworld给编译其读的。两个Makefile不在同一层目录下。 |
| 227 | +touch Makefile |
| 228 | +vim Makefile |
| 229 | +Makefile文件模板内容如下: |
| 230 | +############################################## |
| 231 | +# OpenWrt Makefile for helloworld program |
| 232 | +# |
| 233 | +# |
| 234 | +# Most of the variables used here are defined in |
| 235 | +# the include directives below. We just need to |
| 236 | +# specify a basic description of the package, |
| 237 | +# where to build our program, where to find |
| 238 | +# the source files, and where to install the |
| 239 | +# compiled program on the router. |
| 240 | +# |
| 241 | +# Be very careful of spacing in this file. |
| 242 | +# Indents should be tabs, not spaces, and |
| 243 | +# there should be no trailing whitespace in |
| 244 | +# lines that are not commented. |
| 245 | +# |
| 246 | +############################################## |
| 247 | +include $(TOPDIR)/rules.mk |
| 248 | +# Name and release number of this package |
| 249 | +PKG_NAME:=helloworld |
| 250 | +PKG_RELEASE:=1 |
| 251 | + |
| 252 | +# This specifies the directory where we're going to build the program. |
| 253 | +# The root build directory, $(BUILD_DIR), is by default the build_mipsel |
| 254 | +# directory in your OpenWrt SDK directory |
| 255 | +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) |
| 256 | + |
| 257 | +include $(INCLUDE_DIR)/package.mk |
| 258 | + |
| 259 | +# Specify package information for this program. |
| 260 | +# The variables defined here should be self explanatory. |
| 261 | +# If you are running Kamikaze, delete the DESCRIPTION |
| 262 | +# variable below and uncomment the Kamikaze define |
| 263 | +# directive for the description below |
| 264 | +define Package/helloworld |
| 265 | +SECTION:=utils |
| 266 | +CATEGORY:=Utilities |
| 267 | +TITLE:=Helloworld -- prints a snarky message |
| 268 | +endef |
| 269 | + |
| 270 | +# Uncomment portion below for Kamikaze and delete DESCRIPTION variable above |
| 271 | +define Package/helloworld/description |
| 272 | +If you can't figure out what this program does, you're probably |
| 273 | +brain-dead and need immediate medical attention. |
| 274 | +endef |
| 275 | + |
| 276 | +# Specify what needs to be done to prepare for building the package. |
| 277 | +# In our case, we need to copy the source files to the build directory. |
| 278 | +# This is NOT the default. The default uses the PKG_SOURCE_URL and the |
| 279 | +# PKG_SOURCE which is not defined here to download the source from the web. |
| 280 | +# In order to just build a simple program that we have just written, it is |
| 281 | +# much easier to do it this way. |
| 282 | +define Build/Prepare |
| 283 | +mkdir -p $(PKG_BUILD_DIR) |
| 284 | +$(CP) ./src/* $(PKG_BUILD_DIR)/ |
| 285 | +endef |
| 286 | + |
| 287 | +# We do not need to define Build/Configure or Build/Compile directives |
| 288 | +# The defaults are appropriate for compiling a simple program such as this one |
| 289 | + |
| 290 | +# Specify where and how to install the program. Since we only have one file, |
| 291 | +# the helloworld executable, install it by copying it to the /bin directory on |
| 292 | +# the router. The $(1) variable represents the root directory on the router running |
| 293 | +# OpenWrt. The $(INSTALL_DIR) variable contains a command to prepare the install |
| 294 | +# directory if it does not already exist. Likewise $(INSTALL_BIN) contains the |
| 295 | +# command to copy the binary file from its current location (in our case the build |
| 296 | +# directory) to the install directory. |
| 297 | +define Package/helloworld/install |
| 298 | +$(INSTALL_DIR) $(1)/bin |
| 299 | +$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/ |
| 300 | +endef |
| 301 | + |
| 302 | +# This line executes the necessary commands to compile our program. |
| 303 | +# The above define directives specify all the information needed, but this |
| 304 | +# line calls BuildPackage which in turn actually uses this information to |
| 305 | +# build a package. |
| 306 | +$(eval $(call BuildPackage,helloworld)) |
| 307 | + |
| 308 | +(7)返回到SDK的根目录 |
| 309 | +执行make进行编译 |
| 310 | +编译过程会在build_dir目录下完成 |
| 311 | +编译结果会放在 bin/[yourtarget]/package目录下helloworld_1_bcm47xx.ipk |
| 312 | +(8)上传helloworld_1_bcm47xx.ipk |
| 313 | +使用sftp软件上传helloworld_1_bcm47xx.ipk至路由器 |
| 314 | +执行 opkg install helloworld_1_bcm47xx.ipk |
| 315 | +输入hello然后按Tab键,发现openwrt中已经有helloworld可执行命令。 |
| 316 | +执行 helloworld 查看程序的效果。 |
| 317 | +Hell! O' world, why won't my code compile? |
| 318 | + |
| 319 | + |
0 commit comments