建立 OpenWrt 软件包

1、OpenWrt 目录结构

1.1 根目录

tools、toolchain、include、scripts、target、package、目录为解压OpenWrt后系统自带的目录。
bin、build_dir、staging_dir、dl、feeds 目录为执行相关命令后自动从网络下载目录和编译目录。

clipboard.png

一、feeds
扩展软件包目录。html

# 执行该命令后自动建立feeds目录,并下载相关文件至此目录下。
$ ./scripts/feeds update -a

二、dl
编译前将原始的软件代码包经过网络下载到该目录。ios

# 编译时下载各软件包保存至dl目录下
$ make

三、package
待构建的软件包源码或patch文件。建立自定义软件包时应保存至该目录下。标准软件包目录结构:c++

目录名称 是否可选 说明
Makefile 必选 OpenWrt 构建文件
src 必选 Makefile 或 CMakefile 工程目录
files 可选 配置文件和初始化文件
patches 可选 补丁文件

四、build_dir
自定义软件包会拷贝至该目录的 target-mipsel_mips32_musl 目录下,不一样构建架构目录名称不一样。git

# package 目录下的src软件包会拷贝至此路径下,并执行编译安装操做。
$ build_dir/target-mipsel_mips32_musl/你软件包的src目录内容

五、staging_dir
软件包编译后的安装目录,包含开发板的根目录路径。github

# 开发板根目录路径
$ staging_dir/target-mipsel_mips32_musl/root-brcm47xx/

六、bin
编译完成后生成的安装镜像文件及ipk安装包。网络

七、config
包含全局编译设置、开发人员编译设置、目标文件格式设置和内核编译设置等4部分。多线程

八、include
包含准备环境脚本、下载补丁脚本、编译 Makefile 以及编译指令等。架构

九、scripts
包含准备环境脚本、下载补丁脚本、编译 Makefile 以及编译指令等。app

十、target
指的是嵌入式平台,包括特定嵌入式平台的内容。ide

十一、toolchain
编译器和C库等,例如包含编译工具 gcc 和 glibc 库。

十二、tools
通用命令,用来生成固定的辅助工具,如打补丁工具 patch、编译工具 make 及 squashfs 等。

1.2 重要目录

# 假设自定义工程名为 Hello
#########################################
# Hello
#    - Makefile     // OpenWrt 构建文件
#    + src          // Hello 工程
#       - Makefile  // Hello 工程构建文件
#       - hello.c
#
# openwrt 根目录 ~/openwrt
#########################################


# 工程源码存放路径(手动)
~/openwrt/package/Hello

# 工程源码构建路径(自动)
~/openwrt/build_dir/target-mipsel_mips32_musl/Hello

# 工程目标安装路径(自动,移植后开发板的根目录)
~/openwrt/staging_dir/target-mipsel_mips32_musl/root-brcm47xx

2、编译流程与软件包变量

2.1 编译命令与流程

clipboard.png

说明

  1. 没有 make package/hello/install 命令
  2. 执行 make package/hello/compile 命令时内部会自动执行编译和安装操做
  3. make clean 命令只能删除构建的文件夹,不能删除已安装至 root-brcm47xx 目录下的文件

2.2 软件包变量

  1. openwrt 为 OpenWrt SDK 根目录
  2. 下文的 * 表示软件包目录名称
  • 软件包变量

    变量名 是否可选 含义
    PKG_NAME 必填 The name of the package, as seen via menuconfig and ipkg.
    PKG_RELEASE 必填 The version of this package Makefile
    PKG_VERSION 可选 The upstream version number that we're downloading.
    PKG_BUILD_DIR 可选 Where to compile the original sources
    PKG_SOURCE 可选 The filename of the original sources
    PKG_SOURCE_URL 可选 Where to download the sources from
    PKG_MD5SUM 可选 A Checksum to validate the downlaod
    PKG_CAT 可选 How to decompress the sources(zcat, bzcat, unzip)
    PKG_BUILD_DEPENDS 可选 Packages the need to build before this package, but are not required at runtime.
  • Package/* 软件包描述

    名称 是否可选 描述
    SECTION 目前未使用 软件包类型(可自定义填写)
    CATEGORY 必填 软件包在 menuconfig 中的类别
    DESCRIPTION 已废弃 软件包的完整描述
    URL 可选 从哪里下载原始软件包
    MAINTAINER 可选 维护者信息,便于联系维护者。
    DEPENDS 可选 指定编译该软件包以前必须构建或安装的软件包
    conffiles 可选 该软件包安装的配置文件列表,每一个文件一行。
  • Build/* 软件包构建指令

    名称 是否可选 描述
    Build/Prepare 可选 针对源文件进行解压缩或打补丁的一系列命令,能够不定义。
    Build/Configure 可选 针对配置文件的一些列命令,能够不定义。
    Build/Compile 可选 指定如何编译源文件,绝大部分状况下无需定义。
    Package/package-name/config 可选 可执行PACKAGE或CONFIG相关节点操做
    Package/package-name/install 必填 拷贝源码编译的文件至ipkg
    Package/package-name/preinst 可选 执行Package/install前的脚本,切记包含 #!/bin/sh, return false 退出安装。
    Package/package-name/postinst 可选 执行Package/install后的脚本,切记包含 #!/bin/sh。
    Package/package-name/prerm 可选 删除文件前执行的操做,规则相似Package/preinst
    Package/package-name/postrm 可选 删除文件后执行的操做,规则相似Package/postrm
  • OpenWrt 系统变量

    变量名 变量定义 变量含义 变量值
    $(TOPDIR) ${CURDIR} OpenWrt 根目录 /openwrt
    $(DL_DIR) $(TOPDIR)/dl 经过网络下载的标准软件包 /openwrt/dl
    ${OUTPUT_DIR} $(TOPDIR)/bin 最终编译出的ipk软件包 /openwrt/bin
    ${INCLUDE_DIR} $(TOPDIR)/include 包含文件 /openwrt/include
    $(SCRIPT_DIR) $(TOPDIR)/scripts 脚本文件 /openwrt/scripts
    $(BUILD_DIR_BASE) ??? $(TOPDIR)/build_dir /openwrt/build_dir
    $(PACKAGE_DIR) $(BIN_DIR)/packages

2.3 软件包指令

全部指令位于 rules.mk 文件
指令名称 指令定义 说明
INSTALL_DIR install -d -m0755 建立安装目录
INSTALL_BIN install -m0755 安装可执行文件
INSTALL_SUID install -m4755 -
INSTALL_DATA install -m0644 安装数据文件
INSTALL_CONF install -m0600 安装配置文件

2.4 编译指令

  • 全部软件包编译

    $ make menuconfig
    $ ... 勾选相关软件包保存后退出
    $ make
  • 单个软件包编译

    # 编译并安装软件包
    $ make package/${packageName}/compile
  • 编译选项

    # 编译全部软件包,不输出详细信息,单线程编译
    $ make
    
    # 单线程编译(不带j默认为单线程)
    $ make -j=1
    
    # 多线程编译(指定数目)
    $ make -j=2
    
    # 多线程编译(根据硬件自动)
    $ make -j
    
    # 输出详细信息(默认不输出详细信息)
    $ make V=s
    
    # 组合使用示例
    $ make V=s -j=2
    
    # 说明:
    # 1. 多线程编译速度快,但产生编译错误时不便于定位故障缘由。
    # 2. 想快速编译可采用以下形式:make -j,不输出信息且根据CPU内核数自动多线程编译。
    # 3. 想查看编译错误可采用以下形式:make V=s 或 make V=s -j1。
    # 4. 若是是初次添加自定义软件包,必须先经过 make menuconfig 而后 make 的方式构建。

3、建立基于Makefile的软件包

3.1 文件结构和内容

  • 工程结构
    clipboard.png
  • sprite/Makefile

    include $(TOPDIR)/rules.mk
    
    PKG_NAME:=sprite
    PKG_RELEASE:=1
    PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
    
    include $(INCLUDE_DIR)/package.mk
    
    define Package/$(PKG_NAME)
        SECTION:=utils
        CATEGORY:=Suning
        TITLE:=promote information for $(PKG_NAME).
    endef
    
    define Package/$(PKG_NAME)/description
        This is a Makefile project.
    endef
    
    define Package/$(PKG_NAME)/install
        $(INSTALL_DIR) $(1)/usr/bin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/bin/
    endef
    
    $(eval $(call BuildPackage,$(PKG_NAME)))
    符号 等价值 说明
    $(INSTALL_DIR) install -d -m0755 建立特定权限的 /usr/bin 目录
    $(INSTALL_BIN) install -m0755 修改文件权限并拷贝至/ usr/bin 目录
  • sprite/src/sprite.c

    #include <stdio.h>
    
    int main(void)
    {
         printf("Hello World!\n");
         return 0;
    }
  • sprite/src/Makefile

    CC = gcc
    FLAG = -Wall
    
    sprite:
        $(CC) $(FLAG) sprite.c -o sprite

3.2 构建和清理

  • 编译、安装

    # $(1) 表示目标系统的根目录
    # 或者经过 menuconfig 选中 sprite 选项,执行 make 命令
    $ make package/sprite/compile V=s
  • 删除拷贝的构建目录

    # 删除 ~/openwrt/build_dir/target-mipsel_mips32_musl/sprite
    $ make package/sprite/clean

3.3 构建结果

  • 自动建立的构建目录
    clipboard.png
  • 构建产生的可执行文件
    clipboard.png
  • 构建产生的安装包文件
    clipboard.png
  • 安装至目标系统根目录
    clipboard.png

4、建立基于CMake的软件包

4.1 文件结构和内容

  • 工程结构
    clipboard.png
  • clxye/Makefile

    include $(TOPDIR)/rules.mk
    
    PKG_NAME:=clxye
    PKG_RELEASE:=1
    PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
    
    include $(INCLUDE_DIR)/package.mk
    include $(INCLUDE_DIR)/cmake.mk
    
    define Package/${PKG_NAME}
        SECTION:=utils
        CATEGORY:=Suning
        DEPENDS:=+libstdcpp +libpthread
        TITLE:=promote information for ${PKG_NAME}.
    endef
    
    define Package/${PKG_NAME}/description
        This is a CMake project.
    endef
    
    define Package/${PKG_NAME}/install
        $(INSTALL_DIR) $(1)/usr/bin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/${PKG_NAME} $(1)/usr/bin/
    endef
    
    $(eval $(call BuildPackage,${PKG_NAME}))
    一、CMake 工程必须包含 include $(INCLUDE_DIR)/cmake.mk
    二、C++ 工程必须包含 libstdcpp
  • clxye/src/clxye.cpp

    #include <iostream>
    #include <thread>
    
    int main(void)
    {
        std::thread t( [](){ std::cout << "Hello World!" << std::endl; } );
    
        t.join();
        return 0;
    }
  • clxye/src/Makefile

    # 所需 cmake 工具的最低版本
    cmake_minimum_required(VERSION 2.6)
    
    # 工程名称
    project(clxye)
    
    # 生成可执行程序
    add_executable(${PROJECT_NAME} clxye.cpp )
    
    # 连接共享库
    target_link_libraries(${PROJECT_NAME}
        pthread
    )
    
    # 安装可执行文件(必须提供install)
    install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION "/usr/bin")

4.2 构建和清理

  • 编译、安装

    # 初次编译需采用 make menuconfig、check and save、make V=s 编译
    $ make package/clxye/compile V=s
  • 删除拷贝的构建目录

    # 删除 ~/openwrt/build_dir/target-mipsel_mips32_musl/clxye
    $ make package/sprite/clean

4.3 构建结果

结果与 Makefile 基本一致(clxye与sprite文件名不一样),这里再也不重复展现。

5、依赖软件包

5.1 依赖包类型

  • Package 类型
    image.png
  • Config 类型
    image.png

    config GST1_LIBAV_DECODER_mp3
        bool "MP3 (MPEG Audio Layer 2)"

5.2 选中依赖包

  • DEPENDS 依赖项

    # 此方式只能为 Package 类型,不支持 Config 类型
    define Package/$(PKG_NAME)
    SECTION:=utils
    CATEGORY:=Suning
    DEPENDS:=+libc +libgcc +librt +libpcre +libpthread +pulseaudio-daemon +portaudio \
             +gst1-libav +gstreamer1-libs +libgst1app
    TITLE:=promote information for $(PKG_NAME).
    endef
  • select 方法

    # Package 与 Config 两种类型均支持
    define Package/$(PKG_NAME)/config
        select GST1_LIBAV_DECODER_mp3
        select GST1_LIBAV_PARSER_mpegaudio
        select PACKAGE_gst1-mod-alsa    
        select PACKAGE_gstreamer1-utils
    endef

5.3 GStreamer 最小依赖

efine Package/$(PKG_NAME)
    SECTION:=utils
    CATEGORY:=Suning
    DEPENDS:=+libc +libgcc +librt +libpcre +libpthread +pulseaudio-daemon +portaudio \
             +gst1-libav +gstreamer1-libs +libgst1app
    TITLE:=promote information for $(PKG_NAME).
endef

define Package/$(PKG_NAME)/config
    # ** gst1-libav **
    select GST1_LIBAV_DECODER_ac3
    select GST1_LIBAV_DECODER_mp3
    select GST1_LIBAV_DECODER_pcm_s16be
    select GST1_LIBAV_DECODER_pcm_s16le
    select GST1_LIBAV_DEMUXER_ac3
    select GST1_LIBAV_DEMUXER_mp3
    select GST1_LIBAV_PARSER_ac3
    select GST1_LIBAV_PARSER_mpegaudio

    # ** gstreamer1-plugins-base **
    select PACKAGE_gst1-mod-alsa
    select PACKAGE_gst1-mod-app
    select PACKAGE_gst1-mod-audioconvert
    select PACKAGE_gst1-mod-playback
    select PACKAGE_gst1-mod-typefindfunctions
    select PACKAGE_gst1-mod-volume

    # ** gstreamer1-plugins-good **
    select PACKAGE_gst1-mod-audioparsers
    select PACKAGE_gst1-mod-autodetect
    select PACKAGE_gst1-mod-id3demux
    select PACKAGE_gst1-mod-wavparse

    # ** gstreamer1-utils **
    select PACKAGE_gstreamer1-utils
endef

6、常见问题

一、Makefile:1: *** missing separator. Stop.

# 空格与Tab的问题,进入 Makefile 所在目录执行以下脚本
$ perl -pi -e 's/^  */\t/' Makefile

二、make[2]: Nothing to be done for 'compile'.

# 暂时未找到从根本上解决问题的方法
# 可经过 make menuconfig 勾选后执行 make 操做的方式编译

三、WARNING: your configuration is out of sync. Please run make menuconfig, oldconfig or defconfig!

# 执行 make package/${packagename}/compile 时的编译警告
# 此时必须经过 make menuconfig... save... make 的方式编译,不然 install 会致使目标系统没有安装文件的状况。

四、Package xxx is missing dependencies for the following libraries: libstdc++.so.6

# 添加 c++ 依赖库
DEPENDS:=+libstdcpp

五、Makefile:26: *** Package/clxye is missing the VERSION field. Stop

# Makefile 中该关键字不能省略(不是 PKG_VERSION)
PKG_RELEASE:=1

六、Package/$(PKG_NAME)/install 脚本未执行

# 此时构建目录中未生成 “.pkgdir” 和 “ipkg-mipsel_mips32” 目录。
# 经过 make menuconfig 勾选该软件包,而后再执行 make package/xxx/compile 编译指令,此问题耗费了两天。

参考连接

1. OpenWrt Development Guide
2. Openwrt Examples
3. Creating packages
4. Openwrt package Makefile
5. Makefile 选项 CFLAGS,LDFLAGS,LIBS
6. OpenWRT的包依赖 package DEPEND
7. Alternative for missing __sync_fetch_and_add_8 on MIPS 32-bit
译 《Documentation/kbuild/kconfig-language.txt》
kconfig语法整理)

相关文章
相关标签/搜索