如何进行Makefile的编写?
如何编译动态库?
如何引用动态库?
基础知识
Makefile gcc的参数
-Wall: 是打开警告开关,
-O: 代表默认优化,可选:-O0不优化,-O1低级优化,-O2中级优化,-O3高级优化,-Os代码空间优化。
-g: 是生成调试信息,生成的可执行文件具有和源代码关联的可调试的信息。
-I(大写的i):代表后面跟的目录为第一个寻找头文件的目录
-L: 代表后面跟的目录为第一个寻找库文件的目录
-l(小写的L):表示libxxx.so库文件
-static: 静态编译的
-c(小写): 只编译,不链接
-C(大写): 切换到指定目录再执行 make 过程,makefile 在这个指定目录里面,然后返回到当前目录继续读入、执行当前的Makefile。
gcc -o hello hello.c -I /home/hello/include -L /home/hello/lib -lworld |
android.mk
官方介绍:http://android.mk/
基本概念
可以生成一下几个类别:
JAVA代码的 | C/C++代码的 |
---|---|
JAR包 | 二进制可执行文件:ELF (BUILD_EXECUTABLE) |
应用程序:APK | 动态库:.so (BUILD_SHARED_LIBRARY) |
静态库:.a (BUILD_STATIC_LIBRARY) |
常用的变量:
名字 |
含义 | 常用的方式 |
---|---|---|
LOCAL_PATH |
当前模块的相对路径 | LOCAL_PATH := $(call my-dir) |
LOCAL_MODULE |
编译生成的目标名称 | LOCAL_MODULE := test |
LOCAL_SRC_FILES | 编译该模块需要的源文件 | LOCAL_SRC_FILES := test.c |
LOCAL_C_INCLUDES | 包含C的头文件目录 | |
LOCAL_SHARED_LIBRARIES | 导入共享库 | LOCAL_SHARED_LIBRARIES += liblog |
举例
hejin@desk-ubuntu:/home/desk/myandroid$ ls external/test/ |
分别查看四个源文件的内容:
hejin@desk-ubuntu:/home/desk/myandroid$ cat external/test/test.c |
hejin@desk-ubuntu:/home/desk/myandroid$ cat external/test/test2.c |
hejin@desk-ubuntu:/home/desk/myandroid$ cat external/test/test2.h |
Android.mk:
hejin@desk-ubuntu:/home/desk/myandroid$ cat external/test/Android.mk |
编译
hejin@desk-ubuntu:/home/desk/myandroid$ source build/envsetup.sh |
变量
makefile文件有一个基础的东西就是变量。大家可以自己了解下。这里我们说说android.mk这个变量的不同的地方。主要是用它来做代码管理。
首先在执行make文件的时候这些变量是全局有效的,一些公共的变量会通过include $(CLEAR_VARS)给清除掉。我们这里主要是添加自己的变量。我们在使用自己定义变量的时候有两种情况,一种是在mk中使用,一种是在cpp中使用。注意java不支持的。这两种情况有点不同,请注意。
首先我们得定义这个变量,一般来讲都是在产品的BoardConfig.mk中定义,例如:
TARGET_MEMORY_STYLE := TARGET_MEM_256MB |
这里总共有两个我们经常用的东西。
第一:
如果是mk中使用,定义如前四行就可以了。
变量 := 字符串
在mk中的使用方法就像后面例子一样。
ifeq($(变量),对比值) |
第二:如果你想在cpp中使用,请定义方式如下:
变量 := -D+变量名
如后面几行示例一样的。
如果想在cpp中应用,首先必须在cpp对于的mk文件中,声明如下
LOCAL_CFLAGS += $(BOARD_MEM_FLAGS)
格式: LOCAL_CFLAGS += $(变量)
然后它的cpp中就可以引用如下:
此时去掉了-D前缀。
ifdef TCC_MEM_512MB |
Android.mk变量
这些是您在Android.mk文件中常见的变量,按字母顺序列出。首先,关于变量命名的注释:
LOCAL_ - 这些变量是按模块设置的。它们被行清除
include $(CLEAR_VARS)
,因此您可以在包含该文件后依赖它们为空。您将在大多数模块中使用的大多数变量都是LOCAL_变量。PRIVATE_ - 这些变量是特定于make-target的变量。这意味着它们只能在该模块的命令中使用。这也意味着他们不可能从你的后面的模块背后改变。此 make链接提供了 有关特定于目标的变量的更多信息。
HOST_和TARGET_ - 包含特定于主机或目标版本的目录和定义。不要在makefile中设置以HOST_或TARGET_开头的变量。
BUILD_和CLEAR_VARS - 包含要包含的明确定义的模板makefile的名称。一些示例是CLEAR_VARS和BUILD_HOST_PACKAGE。
任何其他名称都是公平游戏,供您在Android.mk中使用。但是,请记住,这是一个非递归构建系统,因此您的变量可能会被稍后包含的另一个Android.mk更改,并且在执行规则/模块的命令时会有所不同。
定义C/CPP编译的宏时,注意格式,后面=1,不能带空格!
LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1
参数 | 描述 |
---|---|
LOCAL_AAPT_FLAGS | |
LOCAL_ACP_UNAVAILABLE | |
LOCAL_ADDITIONAL_JAVA_DIR | |
LOCAL_AIDL_INCLUDES | |
LOCAL_ALLOW_UNDEFINED_SYMBOLS | |
LOCAL_ARM_MODE | |
LOCAL_ASFLAGS | |
LOCAL_ASSET_DIR | |
LOCAL_ASSET_FILES | 在Android.mk文件中,include $(BUILD_PACKAGE) 将此文件设置为您希望在应用程序中内置的文件集。通常:LOCAL_ASSET_FILES += $(call find-subdir-assets) |
LOCAL_BUILT_MODULE_STEM | |
LOCAL_C_INCLUDES | 指示C / C ++编译器查找头文件的其他目录。这些路径根植于树的顶部。LOCAL_PATH 如果您在包含路径中包含您想要的子目录,请使用 此选项。例如:LOCAL_C_INCLUDES += extlibs/zlib-1.2.3LOCAL_C_INCLUDES += $(LOCAL_PATH)/src 您不应该添加include的子目录 LOCAL_C_INCLUDES ,而应该在#include 语句中引用这些文件及其子目录。例如:#include 不 #include |
LOCAL_CC | 如果要为此模块使用不同的C编译器,请将LOCAL_CC设置为编译器的路径。如果LOCAL_CC为空,则使用相应的默认编译器。 |
LOCAL_CERTIFICATE | |
LOCAL_CFLAGS | 如果您有其他标志要传递到C或C ++编译器,请在此处添加它们。例如:LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 |
LOCAL_CLASSPATH | |
LOCAL_COMPRESS_MODULE_SYMBOLS | |
LOCAL_COPY_HEADERS | 要复制到安装的文件集包括树。你还必须提供LOCAL_COPY_HEADERS_TO 。这会消失,因为复制标题会混淆错误消息,并可能导致人们编辑这些标题而不是正确标题。它还可以更容易地在系统中执行错误的分层,我们希望避免这种分层。我们也没有使用C / C ++ SDK,因此没有最终要求复制任何标头。 |
LOCAL_COPY_HEADERS_TO | “include”中的目录,用于复制LOCAL_COPY_HEADERS to中列出的标题 。这会消失,因为复制标题会混淆错误消息,并可能导致人们编辑这些标题而不是正确标题。它还可以更容易地在系统中执行错误的分层,我们希望避免这种分层。我们也没有使用C / C ++ SDK,因此没有最终要求复制任何标头。 |
LOCAL_CPP_EXTENSION | 如果您的C ++文件以“ .cpp ” 之外的其他内容结尾,则可以在此处指定自定义扩展名。例如:LOCAL_CPP_EXTENSION := .cc 请注意,给定模块的所有C ++文件必须具有相同的扩展名; 目前无法混合不同的扩展。 |
LOCAL_CPPFLAGS | 如果还有其他标志只传递给C ++编译器,请在此处添加。例如:LOCAL_CPPFLAGS += -ffriend-injection``LOCAL_CPPFLAGS 保证LOCAL_CFLAGS 在编译行之后,因此您可以使用它来覆盖中列出的标志 LOCAL_CFLAGS |
LOCAL_CXX | 如果要为此模块使用不同的C ++编译器,请将LOCAL_CXX设置为编译器的路径。如果LOCAL_CXX为空,则使用相应的默认编译器。 |
LOCAL_DX_FLAGS | |
LOCAL_EXPORT_PACKAGE_RESOURCES | |
LOCAL_FORCE_STATIC_EXECUTABLE | 如果您的可执行文件应静态链接,请设置 LOCAL_FORCE_STATIC_EXECUTABLE:=true 。我们以静态形式存在一个非常短的库列表(目前只有libc)。这实际上只用于根文件系统上/ sbin中的可执行文件。 |
LOCAL_GENERATED_SOURCES | 添加到的文件LOCAL_GENERATED_SOURCES 将自动生成,然后在构建模块时链接。有关示例,请参阅自定义工具模板makefile。 |
LOCAL_INSTRUMENTATION_FOR | |
LOCAL_INSTRUMENTATION_FOR_PACKAGE_NAME | |
LOCAL_INTERMEDIATE_SOURCES | |
LOCAL_INTERMEDIATE_TARGETS | |
LOCAL_IS_HOST_MODULE | |
LOCAL_JAR_MANIFEST | |
LOCAL_JARJAR_RULES | |
LOCAL_JAVA_LIBRARIES | 链接Java应用程序和库时,LOCAL_JAVA_LIBRARIES 指定要包含的Java类集。目前有两个:core 和framework 。在大多数情况下,它看起来像这样:LOCAL_JAVA_LIBRARIES := core framework 请注意,LOCAL_JAVA_LIBRARIES 使用“ include $(BUILD_PACKAGE) ” 构建APK时,无需进行设置(并且不允许)。将自动包含适当的库。 |
LOCAL_JAVA_RESOURCE_DIRS | |
LOCAL_JAVA_RESOURCE_FILES | |
LOCAL_JNI_SHARED_LIBRARIES | |
LOCAL_LDFLAGS | 您可以通过设置将其他标志传递给链接器 LOCAL_LDFLAGS 。请记住,参数的顺序对于ld非常重要,因此请测试您在所有平台上执行的操作。 |
LOCAL_LDLIBS | LOCAL_LDLIBS 允许您指定不属于可执行文件或库的构建的其他库。在-lxxx格式中指定所需的库; 它们直接传递给链接线。但是,请记住,不会为这些库生成依赖关系。它在您希望使用主机上预安装的库的模拟器构建中最有用。链接器(ld)是一个特别挑剔的野兽,所以如果你做鬼鬼祟祟的话,有时候必须在这里传递其他标志。一些例子:LOCAL_LDLIBS += -lcurses -lpthreadLOCAL_LDLIBS += -Wl,-z,origin |
LOCAL_MODULE | LOCAL_MODULE 是应该从Android.mk生成的名称。例如,对于libkjs,它LOCAL_MODULE 是“libkjs”(构建系统添加适当的后缀 - .so .dylib .dll)。对于应用程序模块,请使用LOCAL_PACKAGE_NAME 而不是 LOCAL_MODULE 。 |
LOCAL_MODULE_PATH | 指示构建系统将模块放在除其类型之外的其他位置。如果覆盖它,请确保您还设置 LOCAL_UNSTRIPPED_PATH 它是可执行文件还是共享库,以便未提取的二进制文件可以去哪里。如果忘记,将会发生错误。有关更多信息,请参阅将模块置于其 |
LOCAL_MODULE_STEM | |
LOCAL_MODULE_TAGS | 设置LOCAL_MODULE_TAGS 为任意数量的以空格分隔的标记。此变量控制包所包含的构造风格。例如:user :在user / userdebug构建中包含此内容eng :在eng版本中包含此内容tests :目标是测试目标并使其可用于测试optional :不包括这个 |
LOCAL_NO_DEFAULT_COMPILER_FLAGS | |
LOCAL_NO_EMMA_COMPILE | |
LOCAL_NO_EMMA_INSTRUMENT | |
LOCAL_NO_STANDARD_LIBRARIES | |
LOCAL_OVERRIDES_PACKAGES | |
LOCAL_PACKAGE_NAME | LOCAL_PACKAGE_NAME 是应用程序的名称。例如,拨号器,联系人等 |
LOCAL_POST_PROCESS_COMMAND | 对于主机可执行文件,您可以指定在链接后在模块上运行的命令。由于早期或晚期变量评估,您可能必须经历一些扭曲以获得正确的变量:module := $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)LOCAL_POST_PROCESS_COMMAND := /Developer/Tools/Rez -d __DARWIN__ -t APPL\ -d __WXMAC__ -o $(module) Carbon.r |
LOCAL_PREBUILT_EXECUTABLES | 包含$(BUILD_PREBUILT)或$(BUILD_HOST_PREBUILT)时,请将这些设置为要复制的可执行文件。它们自动位于正确的bin目录中。 |
LOCAL_PREBUILT_JAVA_LIBRARIES | |
LOCAL_PREBUILT_LIBS | 包含$(BUILD_PREBUILT)或$(BUILD_HOST_PREBUILT)时,请将这些设置为要复制的库。它们自动位于右侧lib目录中。 |
LOCAL_PREBUILT_OBJ_FILES | |
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES | |
LOCAL_PRELINK_MODULE | |
LOCAL_REQUIRED_MODULES | 设置LOCAL_REQUIRED_MODULES 为任意数量的以空格分隔的模块名称,例如“libblah”或“Email”。如果安装了此模块,则还将安装所需的所有模块。这可用于例如确保在安装给定应用程序时安装必要的共享库或提供程序。 |
LOCAL_RESOURCE_DIR | |
LOCAL_SDK_VERSION | |
LOCAL_SHARED_LIBRARIES | 这些是您直接链接的库。您不需要传递包含传递的库。指定不带后缀的名称:LOCAL_SHARED_LIBRARIES := \ libutils \ libui \ libaudio \ libexpat \ libsgl |
LOCAL_SRC_FILES | 构建系统会查看LOCAL_SRC_FILES 要编译的源文件 - .cpp .c .y .l .java。对于lex和yacc文件,它知道如何自动正确执行中间.h和.c / .cpp文件。如果文件位于包含Android.mk的文件的子目录中,请在其前面加上目录名称:LOCAL_SRC_FILES := \ file1.cpp \ dir/file2.cpp |
LOCAL_STATIC_JAVA_LIBRARIES | |
LOCAL_STATIC_LIBRARIES | 这些是要包含在模块中的静态库。大多数情况下,我们使用共享库,但有几个地方,比如sbin和主机可执行文件中的可执行文件,我们使用静态库代替。LOCAL_STATIC_LIBRARIES := \ libutils \ libtinyxml |
LOCAL_UNINSTALLABLE_MODULE | |
LOCAL_UNSTRIPPED_PATH | 指示构建系统将模块的未剥离版本放在除了其类型的正常之外的某个位置。通常,您重写此操作是因为您LOCAL_MODULE_PATH 为可执行文件或共享库进行了覆盖。如果您覆盖LOCAL_MODULE_PATH 但不是 LOCAL_UNSTRIPPED_PATH ,则会发生错误。有关更多信息,请参阅将模块置于其 |
LOCAL_WHOLE_STATIC_LIBRARIES | 这些是您希望包含在模块中的静态库,而不允许链接器从中删除死代码。如果要将静态库添加到共享库并从共享库中公开静态库的内容,这将非常有用。LOCAL_WHOLE_STATIC_LIBRARIES := \ libsqlite3_android |
LOCAL_YACCFLAGS | 要传递给模块的yacc调用的任何标志。这里的一个已知限制是,对于模块的所有YACC调用,标志都是相同的。这可以修复。如果您需要它,请问。LOCAL_YACCFLAGS := -p kjsyy |
OVERRIDE_BUILT_MODULE_PATH |
Makefile模板
文件目录结构:
- dynamiclibapp.c |
dynamiclib目录
- dynamiclib/inc/dynamiclibs.h (对两个c文件中函数的声明)
文件内容如下:
1 |
- dynamiclib/dynamiclib_add.c 文件内容如下:
1 |
- dynamiclib/dynamiclib_mul.c 文件内容如下:
1 |
- dynamiclib/Makefile 文件内容如下:
1 CC = gcc |
加载
以上文件,就可以生成动态库文件 libmytest.so,应用程序以两种方式加载动态库函数,如下
在编译应用程序时加载动态库
dynamiclibapp.c 文件内容如下
1 |
Makefile 文件内容如下:
1 CC = gcc |
对于这种方式编译出来的动态库文件,还需要在 /etc/ld.so.conf.d/ 目录中添加 libmytest.so 库文件的路径说明,即在 /etc/ld.so.conf.d/ 目录中新建配置文件 mytest.conf,且执行 ldconfig, /etc/ld.so.conf.d/mytest.conf 的文件内容为 libmytest.so 库文件的绝对路径,例如:1 /home/lijiangtao/dynamiclib/libs
如果不在编译应用程序时加载动态库文件里的函数,而是改为在应用程序执行时(比如:程序的main函数启动期间,或在程序执行期间)加载 libmytest.so 里函数,那么就可以不需在 /etc/ld.so.conf.d/ 目录中配置 libmytest.so路径,具体如下所述。
在应用程序执行时加载动态库
dynamiclibapp.c 文件内容如下:
1 |
c/c++ 混合编译
c用gcc编译,c++用g++编译,分别生成.o文件,最后变成最终的库
CC = arm-poky-linux-gnueabi-gcc |
需要注意的是为了能够让C++调用C语言代码,需要在头文件加上extern “C”,代码如下:
|