⬆️ ⬇️

Androgenizer - a tool for assembling sources for Android

This article only covers the adaptation of software build with source code for Unix / Linux on Android.



In my work, I mainly work on updating the functionality of the standard AOSP , so I often have to make decisions on transferring some libraries / applications from Linux to Android. There are many English-language articles on the Internet describing the basic principles of transference and adaptation. Therefore, I decided to collect all the material relating to the software build, put it together and share my experience. The material presented implies that readers have experience building an AOSP and knowledge of the syntax of the Android.mk file.





Why do I need Androigenizer?



Android has its own build system like GNU make . However, most developers are not very happy when they have to add support for a new build system in open source projects (in most cases autotools are used), which, moreover, must be constantly monitored (and suddenly something will break in another version). Androgenizer was created to avoid such situations.

')

Instead of adding an Android.mk file to each module of a project, you can add only one Android.mk file at the topmost level for automatic configuration for the pre-build stage. Perform all steps in autoconf / automake / configure , and then call make in the appropriate directories to create Android.mk files in them.



Each Makefile.am module that you want to compile for Android should contain a small snippet to generate Android.mk using androgenizer .



Sometimes the contents of the Android.mk file depend on how the project will be built: using NDK or as part of AOSP. Androgenizer takes this into account too.



Androgenizer detects the build system based on the ANDROID_BUILD_TOP environment variable , if it is not installed or empty, then it is assumed to be built from under the NDK.




Consider an example of assembling mpeg2enc plug-in from gst-plugins-bad for gstreamer.



Introduction



The entire build will be done using AOSP :



Step 1. Preparing Environment Variables



Consider the creation of the Android.mk file, which will be located along the path “external / gstreamer-aggregate / jni / Android.mk”. Let's take the Android.mk file as a basis and take a closer look:



LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) 


Setting the local path and clearing the values ​​of some variables.



 GSTREAMER_AGGREGATE_TOP := $(abspath $(LOCAL_PATH))/.. 


Setting the top of the directory where the Gstremer sources are located . In our case, the variable GSTREAMER_AGGREGATE_TOP will point to "/ path / to / AOSP / external / gstreamer-aggregate".



 ifneq ($(SYSROOT),) NDK_BUILD := true else NDK_BUILD := false endif 


If the SYSROOT variable is set, then the build is performed using ndk-build, otherwise in the AOSP source code.



 ifeq ($(gstreamer_TOP),) gstreamer_TOP := $(GSTREAMER_AGGREGATE_TOP)/gstreamer endif ifeq ($(GST_PLUGINS_GOOD_TOP),) GST_PLUGINS_GOOD_TOP := $(GSTREAMER_AGGREGATE_TOP)/gst-plugins-bad endif ifeq ($(GST_PLUGINS_BAD_TOP),) GST_PLUGINS_BAD_TOP := $(GSTREAMER_AGGREGATE_TOP)/gst-plugins-bad endif 


Setting global variables where libraries, applications, plugins, etc. are located We will need these variables later for assembly and configuration.



 CONFIGURE_CC := $(TARGET_CC) CONFIGURE_CXX := $(TARGET_CXX) CONFIGURE_INCLUDES := CONFIGURE_LDFLAGS := -lc -ldl # as ndk-build ifeq ($(NDK_BUILD),true) CONFIGURE_CFLAGS := \ -nostdlib -Bdynamic \ -Wl,-dynamic-linker,/system/bin/linker \ -Wl,--gc-sections \ -Wl,-z,nocopyreloc \ $(call host-path,\ $(TARGET_CRTBEGIN_DYNAMIC_O) \ $(PRIVATE_OBJECTS)) \ $(call link-whole-archives,$(PRIVATE_WHOLE_STATIC_LIBRARIES))\ $(call host-path,\ $(PRIVATE_STATIC_LIBRARIES) \ $(TARGET_LIBGCC) \ $(PRIVATE_SHARED_LIBRARIES)) \ $(PRIVATE_LDFLAGS) \ $(PRIVATE_LDLIBS) \ $(call host-path,\ $(TARGET_CRTEND_O)) \ $(CONFIGURE_INCLUDES) CONFIGURE_LDFLAGS += -L$(SYSROOT)/usr/lib -L$(TARGET_OUT) CONFIGURE_INCLUDES += -I$(SYSROOT)/usr/include \ -I$(GSTREAMER_AGGREGATE_TOP)/libid3tag \ -I$(GSTREAMER_AGGREGATE_TOP)/libmad \ -I$(GSTREAMER_AGGREGATE_TOP)/faad/include CONFIGURE_CPP := $(TOOLCHAIN_PREFIX)cpp CONFIGURE_CXX := $(TOOLCHAIN_PREFIX)c++ LIB := $(SYSROOT)/usr/lib # as AOSP build else LIB := $(TARGET_OUT_SHARED_LIBRARIES) CONFIGURE_CC := $(patsubst %,$(PWD)/%,$(TARGET_CC)) CONFIGURE_CXX := $(patsubst %,$(PWD)/%,$(TARGET_CXX)) CONFIGURE_LDFLAGS += -L$(PWD)/$(TARGET_OUT_INTERMEDIATE_LIBRARIES) CONFIGURE_CFLAGS := \ -nostdlib -Bdynamic \ -Wl,-dynamic-linker,/system/bin/linker \ -Wl,--gc-sections \ -Wl,-z,nocopyreloc CONFIGURE_LDFLAGS += \ $(PWD)/$(TARGET_CRTBEGIN_DYNAMIC_O) \ $(call link-whole-archives,$(PRIVATE_WHOLE_STATIC_LIBRARIES))\ $(PRIVATE_STATIC_LIBRARIES) \ $(PWD)/$(TARGET_LIBGCC) \ $(PRIVATE_SHARED_LIBRARIES) \ $(PWD)/$(TARGET_CRTEND_O) CONFIGURE_CPP := $(PWD)/$(TARGET_TOOLS_PREFIX)cpp CONFIGURE_INCLUDES += \ $(foreach incdir, $(realpath $(C_INCLUDES) $(TARGET_C_INCLUDES)), -I$(incdir)) \ -I$(abspath $(TOP)/external/zlib) \ -I$(GSTREAMER_AGGREGATE_TOP)/libid3tag \ -I$(GSTREAMER_AGGREGATE_TOP)/libmad \ -I$(GSTREAMER_AGGREGATE_TOP)/faad/include endif CONFIGURE_CPPFLAGS := \ $(CONFIGURE_INCLUDES) CONFIGURE_CXXFLAGS := \ $(CONFIGURE_INCLUDES) 


Various environment variables required for compilation, linking, etc ...



 # configure as ./autogen.sh CONFIGURE := autogen.sh # or configure as ./configure CONFIGURE := configure 


Executable file to run the configuration.



 CONFIGURE_PKG_CONFIG_LIBDIR := $(GLIB_TOP):$(gstreamer_TOP)/pkgconfig:$(GST_PLUGINS_BASE_TOP)/pkgconfig:$(GST_PLUGINS_GOOD_TOP)/pkgconfig:$(GST_PLUGINS_BAD_TOP)/pkgconfig:$(GSTREAMER_AGGREGATE_TOP)/x264 PKG_CONFIG := PKG_CONFIG_LIBDIR=$(CONFIGURE_PKG_CONFIG_LIBDIR) PKG_CONFIG_TOP_BUILD_DIR="/" pkg-config 


Environment variables for specifying the directories where package configuration files (pc-files) are located. It does not always work, you often have to manually edit or even remove dependencies in files such as configure.ac to complete the configuration successfully.

Pkg-config must be installed on the main system



 GST_CFLAGS := \ -DD_GNU_SOURCE \ -DGST_DISABLE_DEPRECATED \ -DHAVE_CONFIG_H \ -I$(gstreamer_TOP) 


Specific global options for Gstreamer .



 GST_CFLAGS += \ $(shell $(PKG_CONFIG) gstreamer --cflags) 


Add specific global options for Gstreamer from the configuration package. This requires that the “gstreamer” package is installed on the main system. The option is not critical, but it is often useful.



Step 2. Preparing for configuration



Consider the creation of the Android.mk file, which will be located along the path “external / gstreamer-aggregate / gst-plugins-bad / Android.mk”, to configure and create the final Android.mk files for building binary libraries / plug-ins. Let's take the Android.mk file as a basis and take a closer look:



 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) 


Setting the local path and clearing the values ​​of some variables.



 GST_PLUGINS_BAD_TOP := $(LOCAL_PATH) 


Setting the top of the directory where gst-plugins-bad sources are located. In our case, the variable GST_PLUGINS_BAD_TOP will point to "/ path / to / AOSP / external / gstreamer-aggregate / gst-plugins-bad".



 GST_PLUGINS_BAD_BUILT_SOURCES := \ pkgconfig/gstreamer-plugins-bad-1.0-uninstalled.pc \ pkgconfig/gstreamer-plugins-bad-1.0.pc \ gst-libs/gst/baseparse/Android.mk \ gst-libs/gst/basecamerabinsrc/Android.mk \ gst-libs/gst/codecparsers/Android.mk \ gst-libs/gst/interfaces/Android.mk \ gst/h264parse/Android.mk \ ... 


This variable contains the paths and targets for make. For example, we need to go into the folder “gst / h264parse” and execute “make Android.mk”, for this we will execute the command “cd gst / h264parse; make Android.mk ", which is equivalent to the command" make -C 'gst / h264parse' Android.mk "



 GST_PLUGINS_BAD_BUILT_SOURCES := $(patsubst %, $(abspath $(GST_PLUGINS_BAD_TOP))/%, $(GST_PLUGINS_BAD_BUILT_SOURCES)) 


We change relative paths to absolute ones.



 .PHONY: gst-plugins-bad-configure 


Add a "false" goal just in case.



 gst-plugins-bad-configure: cd $(GST_PLUGINS_BAD_TOP) ; \ CC="$(CONFIGURE_CC)" \ CFLAGS="$(CONFIGURE_CFLAGS)" \ CXX="$(CONFIGURE_CXX)" \ CXXFLAGS="$(CONFIGURE_CXXFLAGS)" \ LD=$(TARGET_LD) \ LDFLAGS="$(CONFIGURE_LDFLAGS)" \ CPP=$(CONFIGURE_CPP) \ CPPFLAGS="$(CONFIGURE_CPPFLAGS)" \ PKG_CONFIG_LIBDIR="$(CONFIGURE_PKG_CONFIG_LIBDIR)" \ PKG_CONFIG_TOP_BUILD_DIR=/ \ $(abspath $(GST_PLUGINS_BAD_TOP))/$(CONFIGURE) \ --prefix=/system --host=arm-linux-androideabi \ --disable-gtk-doc \ --disable-valgrind && \ for file in $(GST_PLUGINS_BAD_BUILT_SOURCES); do \ rm -f $$file && \ make -C $$(dirname $$file) $$(basename $$file) ; \ done 


Create a gst-plugins-bad-configure target.

When configuring, we always specify the option "--prefix = / system", since by default in Android all system libraries, applications, settings, etc. located in the / system folder

For ARM systems, be sure to specify the option "--host = arm-linux-androideabi".

The remaining configuration options depend on your requirements, desires and capabilities.

If necessary, you can use additional commands to clean the source "make distclean" and / or "autoreconf -fiv" before configuring.



 -include $(GST_PLUGINS_BAD_TOP)/gst-libs/gst/baseparse/Android.mk -include $(GST_PLUGINS_BAD_TOP)/gst-libs/gst/basecamerabinsrc/Android.mk -include $(GST_PLUGINS_BAD_TOP)/gst-libs/gst/codecparsers/Android.mk -include $(GST_PLUGINS_BAD_TOP)/gst-libs/gst/interfaces/Android.mk -include $(GST_PLUGINS_BAD_TOP)/gst/h264parse/Android.mk ... 


And at the very end are the paths to the Android.mk files that will collect libraries, applications, plugins, etc.



Step 3. Adding a target to the Makefile



Consider adding the “Android.mk” target to the Makefile.am file, which will be located along the path “external / gstreamer-aggregate / gst-plugins-bad / ext / mpeg2enc / Makefile.am”, to build the Android.mk file to build the binary plugin. Let's take the Makefile.am file as a basis and take a closer look:



 plugin_LTLIBRARIES = libgstmpeg2enc.la 


Plugin name



 libgstmpeg2enc_la_SOURCES = \ gstmpeg2enc.cc \ gstmpeg2encoptions.cc \ gstmpeg2encoder.cc \ gstmpeg2encstreamwriter.cc \ gstmpeg2encpicturereader.cc 


Source files required for build



 libgstmpeg2enc_la_CXXFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CXXFLAGS) $(MPEG2ENC_CFLAGS) libgstmpeg2enc_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ \ $(GST_LIBS) $(MPEG2ENC_LIBS) libgstmpeg2enc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstmpeg2enc_la_LIBTOOLFLAGS = --tag=disable-static 


Flags for compilation and linking



 noinst_HEADERS = \ gstmpeg2enc.hh \ gstmpeg2encoder.hh \ gstmpeg2encoptions.hh \ gstmpeg2encstreamwriter.hh \ gstmpeg2encpicturereader.hh 


Header files



We have everything you need to create the goal "Android.mk"

 Android.mk: Makefile.am $(BUILT_SOURCES) androgenizer \ -:PROJECT libgstmpeg2enc -:SHARED libgstmpeg2enc \ -:TAGS eng debug \ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \ -:SOURCES $(libgstmpeg2enc_la_SOURCES) \ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstmpeg2enc_la_CXXFLAGS) \ -:LDFLAGS $(libgstmpeg2enc_la_LDFLAGS) \ $(libgstmpeg2enc_la_LIBADD) \ -ldl \ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \ LOCAL_CPP_EXTENSION:='.cc' \ > $@ 


It is necessary to pay attention to LOCAL_CPP_EXTENSION , I set the ".ss" forcibly, since by default Android uses the extension "cpp". There are always problems if the project stores several files with different extensions “cxx”, “cpp” and “cc”.



Translation options androgenizer , which can be found in the README.txt .

more
  • -: PROJECT Project name. The parameter must be called first and only once.



  • -: SUBDIR adds -include , in addition to the declared variable ‹project› _TOP



  • Replacement path for -I inclusions

    • -: ABS_TOP sets the absolute path to the source folder
    • -: REL_TOP sets the relative path to the source folder


    It should always be: -: REL_TOP $ (top_srcdir) -: ABS_TOP $ (abs_top_srcdir)



  • Types of modules created:

    • -: STATIC creates a static library for the target system (BUILD_STATIC_LIBRARY)
    • -: SHARED creates a dynamic library for the target system (BUILD_SHARED_LIBRARY)
    • -: EXECUTABLE creates an executable file for the target system (BUILD_EXECUTABLE)
    • -: HOST_STATIC creates a static library for the host (BUILD_HOST_STATIC_LIBRARY)
    • -: HOST_SHARED creates a dynamic library for the host (BUILD_HOST_SHARED_LIBRARY)
    • -: HOST_EXECUTABLE creates an executable file for the host (BUILD_HOST_EXECUTABLE)


    Multiple modules can be created using a single command line.



  • Additional resources for modules (you must first declare a module!):

    • -: SOURCES source file list



      • -: CFLAGS flags for C compiler
      • -: CXXFLAGS flags for C ++ compiler
      • -: CPPFLAGS flags for C preprocessor


      CPPFLAGS is used by C and C ++ compilers

      CFLAGS is used by C and C ++ compilers.

      CXXFLAGS is used only by the C ++ compiler



      Android uses various conventions, so don’t be surprised if CXXFLAGS is at the end of LOCAL_CPPFLAGS in Android.mk

      There is no way to pass only the C compiler flags to the Android build system.



      All -I flags in any of CFLAGS, CPPFLAGS or CXXFLAGS will be added to LOCAL_C_INCLUDES without "-I".



      some flags are deleted without warning: -Werror -pthread



    • -: LDFLAGS linker options list:

      • -l ‹foo› add as lib ‹foo› to LOCAL_SHARED_LIBRARIES
      • -L and -R will be deleted without warning.
      • -pthread and -lpthread will be deleted without warning
      • -lrt will be deleted without warning (rt built-in library in bionic)
      • -no-undefined will be deleted without warning.
      • -dlopen , -version-info , and the words following them (optional arguments) will be deleted without warning
      • Only files * .a and * .la are saved, the rest will be deleted without warning.


    • -: LIBFILTER_STATIC library list (without “lib” prefix and extension)

      These libraries will be added to LOCAL_STATIC_LIBRARIES and excluded from LOCAL_SHARED_LIBRARIES.



    • -: LIBFILTER_WHOLE library list (without “lib” prefix and extension)

      These libraries will be added to LOCAL_WHOLE_STATIC_LIBRARIES.



    • -: TAGS must include any of the parameters: optional user eng tests



    • -: HEADERS header file list for LOCAL_COPY_HEADERS



    • -: HEADER_TARGET sets LOCAL_COPY_HEADERS_TO, it may include several lines, but only the last one is saved



    • -: PASSTHROUGH list of strings embedded in the current module configuration. For example LOCAL_ARM_MODE: = arm



    • -: END optional ... may be removed in the future. Ends the description of the current module, and begins the description of the next one.








Step 4. Build



Download androgenizer , collect and put the program, where it will be visible from the PATH environment variable.

Now we are ready to assemble the module. To do this, go to the root AOSP and execute the command:

 make gst-plugins-bad-configure 


After some time, gst-plugins-bad will be configured and the output will be the finished Android.mk file:

external / gstreamer-aggregate / gst-plugins-bad / ext / mpeg2enc / Android.mk
 LOCAL_PATH:=$(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE:=libgstmpeg2enc LOCAL_MODULE_TAGS:=eng debug LOCAL_SRC_FILES := \ gstmpeg2enc.cc \ gstmpeg2encoptions.cc \ gstmpeg2encoder.cc \ gstmpeg2encstreamwriter.cc \ gstmpeg2encpicturereader.cc LOCAL_SHARED_LIBRARIES:=\ libglib-2.0 \ libgobject-2.0 \ libgstreamer-0.10 \ libgstbase-0.10 \ libgstriff-0.10 \ libgsttag-0.10 \ libgstvideo-0.10 \ libdl LOCAL_LDFLAGS:=\ -module\ -avoid-version\ -export-symbols-regex\ -no-undefined\ -Wl,-Bsymbolic-functions LOCAL_CFLAGS := \ -DHAVE_CONFIG_H \ -I. \ -I/path/to/AOSP/external/gstreamer-aggregate/gst-plugins-bad \ -I/path/to/AOSP/external/gstreamer-aggregate/gst-plugins-bad/gst-libs \ -I/path/to/AOSP/external/gstreamer-aggregate/gst-plugins-base \ -I/path/to/AOSP/external/gstreamer-aggregate/gst-plugins-base/gst-libs \ -I/path/to/AOSP/external/gstreamer-aggregate/gstreamer \ -I/path/to/AOSP/external/gstreamer-aggregate/glib/glib \ -I/path/to/AOSP/external/gstreamer-aggregate/glib \ -I/path/to/AOSP/external/gstreamer-aggregate/glib/gmodule \ -I/path/to/AOSP/external/gstreamer-aggregate/gstreamer/libs \ -DG_THREADS_MANDATORY \ -DG_DISABLE_DEPRECATED \ -Wall \ -Wdeclaration-after-statement \ -Wvla \ -Wpointer-arith \ -Wmissing-declarations \ -Wmissing-prototypes \ -Wredundant-decls \ -Wundef \ -Wwrite-strings \ -Wformat-nonliteral \ -Wformat-security \ -Winit-self \ -Wmissing-include-dirs \ -Waddress \ -Waggregate-return \ -Wno-multichar \ -Wnested-externs \ -Wno-unused \ -g \ -DGST_DISABLE_DEPRECATED LOCAL_PRELINK_MODULE := false LOCAL_ARM_MODE:=arm LOCAL_MODULE_PATH:=$(TARGET_OUT)/lib/gstreamer-0.10 LOCAL_CPP_EXTENSION:=.cc include $(BUILD_SHARED_LIBRARY) 






Results



Advantages:



Disadvantages:





Articles used:

Source: https://habr.com/ru/post/164139/



All Articles