android 系统源码编译-cmake基础技巧系列教程

本教程为纯干货教程系列,内容原创android 系统源码编译,持续更新,欢迎关注转发

废话不多说,干货。 上图显示cmake是一个跨平台编译工具。 当公司的一套代码运行在多个平台上时,例如:android、ios、windows、linux可以同时用cmake编译。 事实上,不同的平台需要配置不同的编译环境。 比如android需要配置ndk,ios需要配置xcode。 该配置稍后会继续输出。 欢迎关注。 明天我们来谈谈基本命令。

本文内容由简单到复杂,最后是一个小项目的完整示例。 本系列教程从本文的基本技巧开始。 欢迎继续关注

cmake句型和shell句型类似,都支持大小写

命令名称([可选])

项目

项目的基本设置

project( [LANGUAGES] [...])
project(
        [VERSION [.[.[.]]]]
        [LANGUAGES ...])

实施例1

project(test C) 

实施例2

# 项目信息
project( demo1
         VERSION 1.2.3
         DESCRIPTION "项目描述,比如:本项目非常牛逼"
         HOMEPAGE_URL "项目地址,比如:https://github.com/XXX/YYY"
         LANGUAGES CXX
        )

set命令是变量的形参,可以内置到cmake中,也可以自定义

设定系统自带的变量

set( CMAKE_CXX_FLAGS "-std=c++11" )//以flags的形式的实现通知使用版本
set(CMAKE_CXX_STANDARD 11)//以命令形式通知使用版本

设置自定义变量

set(THIRD_PART "${CMAKE_CURRENT_SOURCE_DIR}/src/third/include")//设置头文件的搜索路径
include_directories(${THIRD_PART})

添加定义

添加预处理的标志显然就是添加宏定义

add_definitions(-DFOO -DBAR ...)

添加方式有两种:

例子:

例如,您的代码中可能有这样的内容:

#ifdef TEST
//TODO if
#else
//TODO else
#endif

那么为什么不改变代码而是通过编译后的脚本来控制宏,它使用了这个命令:add_definitions,如下所示

add_definitions("-DTEST")

这时,TEST宏就会在预处理阶段与源代码结合起来。

包含目录

指定包含的头文件的搜索路径

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

注意:如果路径中有空格,需要用双冒号括起来 aux_source_directory

为某个目录下的所有源代码文件设置一个变量名,以便以后所有源代码文件都可以替换为变量名。 例如,可以与add_library一起使用生成静态库,方便指定子构建系统的完整库类型和名称。

aux_source_directory( )

组合使用命令示例

aux_source_directory(. DIR_LIB_SRC)
add_library(mylib STATIC ${DIR_LIB_SRC})

分析:将该目录下的所有源代码文件设置为变量DIR_LIB_SRC,然后创建动态库。

添加库

将源代码编译到指定的库中(类型+名称)

add_library( [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [source1] [source2 ...])

生成库的目的和作用命令的组合使用例1.1:外部提供库文件的Android将源代码编译成动态库

add_library(
        # Specifies the name of the library.
        libDemo
        # Sets the library as a shared library.
        SHARED
        # Provides a relative path to your source file(s).
        src/main/jni/test1.cpp
        src/main/jni/test2.cpp
        src/main/jni/test3.cpp
)

例1.2:外部提供库文件的Android将源代码编译成动态库并与aux_source_directory结合使用

aux_source_directory(./src/main/jni custom)
add_library(
        # Specifies the name of the library.
        libDemo
        # Sets the library as a shared library.
        SHARED
        # Provides a relative path to your source file(s).
        ${custom}
)

例1.3:外部提供库文件的非Android示例

它本质上与android示例相同,属于子构建系统。 区别在于:android没有顶层构建直接与jni通信,非android有顶层构建通过add_subdirectory添加子构建系统

aux_source_directory(. SUBLIB1_SRC)
add_library(subLib1 ${SUBLIB1_SRC})

示例 2:结合 target_link_libraries 执行顶级构建

add_library和target_link_libraries组合起来构建一个顶层编译系统,一般是为了向外界提供库文件,比如android的建立

aux_source_directory(./ TOP_SRCS)
add_library(libraryLink SHARED ${TOP_SRCS})
target_link_libraries(
    libraryLink
)

添加子目录

多编译系统,即多个CMakeList.txt,非顶层构建都是子构建系统。 子构建系统通过add_library生成构建库文件android 系统源码编译,顶层构建如何与子构建系统关联使用这个命令。

将子目录添加到构建中。

add_subdirectory(source_dir [binary_dir]
                 [EXCLUDE_FROM_ALL])

例子:

add_subdirectory(./subLib1)

注意:该命令唯一需要的选项是子编译系统目录,子编译系统目录,而不是子编译系统生成的库名target_link_libraries

链接所有库、子编译系统和库文件

例子:

cmake_minmum_required(VERSION 3.4.1)
project(linkDemo CXX)
//1. 添加子编译系统
add_subdirectory(./sublib)
//2. 顶级编译系统
aux_source_directory(./ TOP_SRCS)
add_executable(linkDemo ${TOP_SRCS})
//3. 第三方库
set(THIRD_PART "${CMAKE_CURRENT_SOURCE_DIR}/src/third/include")
include_directories(${THIRD_PART})
message("third part include path = ${THIRD_PART}")
message("thrid part libs path = ${THIRD_PART}/libs/XXX.a")
//4. 链接:子系统+顶级系统+第三方库
target_link_libraries(
    linkDemo
    sublib
    "${THIRD_PART}/libs/XXX.a"
)

本文为VX同名公众号原创,欢迎关注

抱歉,这周真的很忙。 。 。 废话不多说,直接进入正题。

前言

所谓分析思路无非就是找到程序的入口点,按照执行流程一步步阅读分析,或者从自己感兴趣的部分开始。这个系列还不是对Lua的全面分析,但只选取其中一部分进行分析。 为此,我们要找到自己感兴趣的部分lua源码编译,并有针对性地进行分析。

因为Lua的官方文档比较完整,所以我们在浏览完官方资料之后就比较容易开始分析。

所谓源代码分析,就是从源代码中重构出可执行程序,调试调试,看执行过程,看主要数据结构和算法,程序的运行状态等,最后品味设计(问题背景、原因等、优缺点),仅此而已。

我们先看一下源代码的布局。

代码布局

可以从Makefile开始,但是这里我们使用的是Windows+VisualStudio,所以这一步可以省略。

查看从官网下载的源码包,提供了以下文件:

./lua-5.3.0/
    Makefile    README
    /doc/
        contents.html      logo.gif      lua.1
        lua.css            luac.1        manual.css
        manual.html        osi-certified-72x60.png
        readme.html
    /src/
        lapi.c       lapi.h       lauxlib.c    lauxlib.h
        lbaselib.c   lbitlib.c    lcode.c      lcode.h
        lcorolib.c   lctype.c     lctype.h     ldblib.c
        ldebug.c     ldebug.h     ldo.c        ldo.h
        ldump.c      lfunc.c      lfunc.h      lgc.c
        lgc.h        linit.c      liolib.c     llex.c
        llex.h       llimits.h    lmathlib.c   lmem.c
        lmem.h       loadlib.c    lobject.c    lobject.h
        lopcodes.c   lopcodes.h   loslib.c     lparser.c
        lparser.h    lprefix.h    lstate.c     lstate.h
        lstring.c    lstring.h    lstrlib.c    ltable.c
        ltable.h     ltablib.c    ltm.c        ltm.h
        lua.c        lua.h        lua.hpp      luac.c
        luaconf.h    lualib.h     lundump.c    lundump.h
        lutf8lib.c   lvm.c        lvm.h        lzio.c
        lzio.h       Makefile

第一件事实际上是阅读 README。 不用说,其实专业的做法可以是阅读Makefile。 这里,为了防止引入其他不相关的知识,使用了简单的技术。

根据说明查看doc/readme.html文件中的[BuildingLuaonothersystems]部分,我们发现它介绍了lua可执行程序的大致组成和依赖关系,如下:

library:
        lapi.c          lcode.c         lctype.c        ldebug.c
        ldo.c           ldump.c         lfunc.c         lgc.c
        llex.c          lmem.c          lobject.c       lopcodes.c
        lparser.c       lstate.c        lstring.c       ltable.c
        ltm.c           lundump.c       lvm.c           lzio.c
        lauxlib.c       lbaselib.c      lbitlib.c       lcorolib.c
        ldblib.c        liolib.c        lmathlib.c      loslib.c
        lstrlib.c       ltablib.c       lutf8lib.c      loadlib.c
        linit.c
interpreter:
        library,        lua.c
compiler:
        library,        luac.c

根据这个简单的依赖关系,我用VS2015构建了相应的项目进行调试。 虽然官方数据集中也提供了现成的VS项目下载链接:

TODO:这里应该有一个下载链接^_^

因为我们分析的重点是编译原理和虚拟机部分,而不是相关库的实现部分。 因此,我们应该从lua.c或者luac.c开始,虽然从文件列表中我们也可以看到上面有几个重要的文件:

llex.clopcodes.clparser.clvm.c

至于从哪里开始更好,这是一个意见问题。 这里我还是用官方的资料来帮助选择。

官方数据集的 wiki 中提供了一个页面。 本页描述了该文件的用途、编程约定、模块结构等。

为了防止这个页面失效,我还是无耻的把下面的翻译复制粘贴过来给大家提供翻译。 网上也有一些翻译,但是省略了一些我认为翻译时有用的信息。 一些简单的我就不翻译了。

Lua源码模块结构、实用功能模块、基本数据类型实现模块

lobject.c - Lua 对象的一些通用函数。 包括:

lstring.c-stringtable(保存Lua处理的所有字符串)

lfunc.c - 用于操作原型和闭包的辅助函数。

ltable.c - Luatables(哈希)

句子分析和代码生成相关模块

ldump.c - 用于保存预编译的Lua代码块:

处理Lua字节码执行的模块

lvm.c-Lua虚拟机:

ldo.c-Lua函数调用和堆栈管理。处理函数调用(luaD_call/luaD_pcall)、堆栈增长、解释器处理等。

ltm.c - 标签方法。 实现了查询对象元方法的功能。

标准库的实现模块

lbaselib.c - (base functions)
lstrlib.c  - string
ltablib.c  - table
lmathlib.c - math
loslib.c   - os
liolib.c   - io
loadlib.c  - package
ldblib.c   - debug

android 系统源码编译-cmake基础技巧系列教程

以下模块定义了CAPIlua和luac程序感兴趣模块的实现模块

认识了Lua的模块结构之后,我们需要注意分析的模块就下来了:

其实后期如果有时间我会再分析一下Lua的垃圾收集器,不过最近太忙了。

从Makefile查看模块之间的依赖关系

以下摘录了lua-5.3.0/src/Makefile的重要部分

LUA_A=    liblua.a
CORE_O=    lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o 
    lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o 
    ltm.o lundump.o lvm.o lzio.o
LIB_O=    lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o  
    lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o
BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
LUA_T=    lua
LUA_O=    lua.o
LUAC_T=    luac
LUAC_O=    luac.o

根据我们感兴趣的模块,大致有以下目标文件:

lua.o

luac.o

llex.o

ldo.o

android 系统源码编译-cmake基础技巧系列教程

lstate.o

lparser.o

opcodes.o

lvm.o

lcode.o

转储文件

lundump.o

ltm.o

lobject.o

lstring.o

ltable.o

android 系统源码编译-cmake基础技巧系列教程

lfunc.o

(我不得不抱怨 Markdown 编辑器的 bug,并以某种方式手动将其他条目加粗......我根本没有那样写!!!)

虽然还是不少,但比较重要的都用斜体标出。 大致按照这个顺序来分析。 虽然那些也可以直接看源文件中引用的头文件,但是那样太麻烦了。 不过,有时候Lua源码并没有把include命令写在文件的底部,而是写在中间的某个地方,这就更操蛋了。 看Makefile更方便更专业。 我们继续看看Makefile中上述目标文件的依赖关系:

lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
luac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h lobject.h llimits.h 
  lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldo.h 
  lobject.h lstate.h ltm.h lzio.h lmem.h lgc.h llex.h lparser.h lstring.h 
  ltable.h
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h 
  lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h 
  lparser.h lstring.h ltable.h lundump.h lvm.h
lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h 
  lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h 
  lstring.h ltable.h
lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h 
  llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h 
  ldo.h lfunc.h lstring.h lgc.h ltable.h
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h
lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h 
  llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h 
  ltable.h lvm.h
lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h 
  llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h 
  ldo.h lgc.h lstring.h ltable.h lvm.h

这里简单介绍一下Makefile句型:引号左边的.o是编译时生成的目标文件,逗号左边是生成目标文件所需的源文件。 上面的Makefile代码中,等号右边是变量,等号左边是变量的值。

关于Makefile:Makefile是GNU/Linux系统中用于手动创建的DSL,由gnumake使用,类似于Android开发中的.gradle文件。 然而,VS 和 Qt 也都使用自己的 Makefile 格式和工具。 VS有nmake,Qt有qmake,跨平台有cmake,这里就不赘述了,自己看文档即可。

现在lua源码编译,我们可以更有针对性地查看源文件了。

关于下一期

下一期我会介绍一下Lua源码中的编程约定(虽然我还是一个搬运工+翻译家,但是这里的翻译就靠运气了,翻译质量应该问题不大)。 以上问题比较无聊,又缺一不可,所以只能忍了。 预测,明天更新第三弹。

参考

模块化结构简介

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 android 系统源码编译-cmake基础技巧系列教程 https://www.wkzy.net/game/126538.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务