Android-Build-System: Android.mk(1) Grundkonzept, Zuweisungsvariablenreferenz, ausführliche Erklärung

In diesem Blog besprechen wir die Verwendung von Zuweisungsoperationen, Variablenverweisen und Funktionen in der Android.mk-Datei sowie Beispiele für statische Bibliotheken und ausführbare Dateien. Durch die Verwendung dieser Konzepte können Sie die Variablen und Ausdrücke in der Android.mk-Datei flexibler steuern, um eine kundengerechte Funktionalität zu erreichen.

Android-Build-System: Android.mk(1) Grundkonzept, Zuweisungsvariablenreferenz, detaillierte Erklärung
Android-Build-System: Android.mk(2)-Funktion, detaillierte Erklärung
Android-Build-System: Detaillierte Erläuterung der Zustandssteuerung von Android.mk(3)

Studienreferenz:

Android.mk | Android NDK | Android-Entwickler – Android-Entwickler.

1. Was ist Android.mk?

Android.mk ist eine Datei, die den Erstellungsprozess eines Android-Projekts beschreibt. Es handelt sich um eine Erweiterung, die auf der Makefile-Syntax basiert. Die Rolle und Bedeutung von Android.mk liegt in:

  • Sie können definieren, welche Quelldateien, Ressourcendateien, Bibliotheksdateien usw. im Projekt enthalten sind, sowie die Abhängigkeiten zwischen ihnen.
  • Sie können die Kompilierungsoptionen, Linkoptionen, Präprozessordefinitionen usw. des Projekts sowie die Anpassung an verschiedene Plattformen und Architekturen festlegen.
  • Sie können den Ausgabetyp des Projekts steuern, z. B. ausführbare Dateien, statische Bibliotheken, dynamische Bibliotheken, APKs usw., sowie deren Installationsort und Berechtigungen.
  • Einige integrierte Funktionen und Variablen können aufgerufen werden, um komplexe Logik und Funktionen zu implementieren.

2. Grundaufbau von Android.mk

Eine typische Android.mk-Datei besteht aus den folgenden Teilen:

  • Kommentare: Zeilen, die mit # beginnen, sind Kommentare und werden nicht analysiert.
  • Leerzeilen: Leerzeilen werden ignoriert und haben keinen Einfluss auf die Analyse.
  • Zuweisungsoperation: Die Zuweisungsoperation wird verwendet, um einer Variablen einen Wert zuzuweisen. Es stehen verschiedene Zuweisungsoperatoren zur Auswahl.
  • Variablenreferenz: Die Variablenreferenz wird verwendet, um den Wert einer Variablen zu erhalten. Es stehen mehrere Referenzmethoden zur Auswahl.
  • Funktion: Eine Funktion ist eine spezielle Variable, die Parameter akzeptieren und Ergebnisse zurückgeben kann. Es stehen eine Vielzahl integrierter Funktionen und benutzerdefinierter Funktionen zur Verfügung.
  • Bedingte Anweisung: Bedingte Anweisungen werden verwendet, um verschiedene Operationen basierend auf Bedingungen auszuführen. Es stehen verschiedene bedingte Beurteilungssymbole zur Auswahl.
  • Steueranweisung: Die Steueranweisung wird verwendet, um den Ausführungsfluss des Codeblocks zu steuern. Es stehen verschiedene Steuerschlüsselwörter zur Auswahl.
  • Druckvorgang: Der Druckvorgang dient der Ausgabe von Informationen auf dem Terminal. Es stehen verschiedene Druckfunktionen zur Verfügung.
  • Moduldefinition: Die Moduldefinition ist der wichtigste Teil der Android.mk-Datei. Sie wird verwendet, um ein oder mehrere Gebäudemodule zu definieren und deren Eigenschaften und Verhalten anzugeben.

In dieser Android.mkl-Reihe werden die spezifischen Inhalte und die Verwendung dieser Teile nacheinander vorgestellt. Bitte lesen Sie sie später.

3. Zuweisungsvorgang

Die Zuweisungsoperation ist eine der häufigsten Grundoperationen in der Datei Android.mk. Sie wird verwendet, um einer Variablen einen Wert zuzuweisen oder den Wert einer vorhandenen Variablen zu ändern. In der Makefile-Syntax stehen vier Zuweisungsoperatoren zur Auswahl: :=, +=, ?= und a>=. Ihre Bedeutung und Verwendung ist wie folgt:

  • :=: Dieser Zuweisungsoperator stellt eine unmittelbare Zuweisung dar, d. h. beim Parsen der Zuweisungsanweisung wird der Wert des Ausdrucks auf der rechten Seite berechnet und der Variablen auf der linken Seite zugewiesen. Zum Beispiel:
# 使用:= 赋值操作符
file_name := source_file
# 打印file_name的值
$(warning file_name is $(file_name)) # 输出 file_name is source_file
# 改变file_name的值
file_name := header_file
# 再次打印file_name的值
$(warning file_name is $(file_name)) # 输出 file_name is header_file
  • +=: Dieser Zuweisungsoperator stellt eine Anhängezuweisung dar, das heißt, er fügt den Wert des Ausdrucks rechts nach dem ursprünglichen Wert der Variablen hinzu und weist ihn der Variablen links zu. Zum Beispiel:
# 使用:= 赋值操作符
file_extension := .txt
# 打印file_extension的值
$(warning file_extension is $(file_extension)) # 输出 file_extension is .txt
# 使用+= 追加赋值操作符
file_extension += .bak
# 再次打印file_extension的值
$(warning file_extension is $(file_extension)) # 输出 file_extension is .txt.bak
  • ?=: Dieser Zuweisungsoperator stellt eine bedingte Zuweisung dar, dh der Wert nach dem Gleichheitszeichen wird nur dann zugewiesen, wenn die Variable nicht zugewiesen wurde. Wenn der Variablen bereits ein Wert zugewiesen wurde, wird die Zuweisung hier nicht wirksam. Zum Beispiel:
# 使用:= 赋值操作符
project_name := MyProject
# 打印project_name的值
$(warning project_name is $(project_name)) # 输出 project_name is MyProject
# 使用?= 条件赋值操作符
project_name ?= NewProject
# 再次打印project_name的值
$(warning project_name is $(project_name)) # 输出 project_name is MyProject  # 注意这里的结果没有改变,因为 project_name 已经被赋值过了

  • =: Dieser Zuweisungsoperator stellt eine verzögerte Zuweisung dar, dh der Wert der Variablen wird nur erweitert, wenn die Variable verwendet wird. Das heißt, wenn der Wert einer Variablen später geändert wird, ändern sich auch die Orte, an denen die Variable zuvor verwendet wurde. Zum Beispiel:
# 使用= 延迟赋值操作符
output_dir = build
# 打印output_dir的值
$(warning output_dir is $(output_dir)) # 输出 output_dir is build 
# 改变output_dir的值
output_dir = dist # 注意这里不是使用 := ,而是使用 =
# 再次打印output_dir的值
$(warning output_dir is $(output_dir)) # 输出 output_dir is dist 

# 使用:= 赋值操作符
config := debug
# 使用$(变量名) 引用变量的值
$(warning config is $(config)) # 输出 config is debug

# 使用:= 赋值操作符
config := release
# 使用${变量名} 引用变量的值
$(warning config is ${config}) # 输出 config is release

4. Variablenreferenz

Mithilfe der Variablenreferenz wird der Wert einer Variablen ermittelt. Es stehen zwei Referenzmethoden zur Auswahl:

  • $(变量名): Bei dieser Methode wird der Wert der Variablen abgerufen und am Referenzort ersetzt. Zum Beispiel:
# 使用:= 赋值操作符
VAR := hello1
# 使用$(变量名) 引用变量的值
$(warning VAR is $(VAR)) # 输出 VAR is hello1
  • ${变量名}: Diese Methode entspricht der vorherigen Methode, verwendet jedoch andere Klammern. Zum Beispiel:
# 使用:= 赋值操作符
VAR := hello2
# 使用${变量名} 引用变量的值
$(warning VAR is ${VAR}) # 输出 VAR is hello2

Variablenreferenzen haben in Android.mk-Dateien viele praktische Anwendungen, wie zum Beispiel:

  • Definieren Sie die Bibliotheksdateiliste: Sie können eine Variable zum Speichern der Bibliotheksdateiliste verwenden und dann in der Moduldefinition auf die Variable verweisen. Zum Beispiel:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 定义源文件列表
LOCAL_SRC_FILES_APP := \
    src/main.cpp \
    src/foo.cpp \
    src/bar.cpp

# 定义库文件列表
LOCAL_SHARED_LIBRARIES := libmylib

# 构建libmylib动态库
include $(CLEAR_VARS)
LOCAL_MODULE := libmylib
LOCAL_SRC_FILES := libsrc/libmylib.cpp
include $(BUILD_SHARED_LIBRARY)

Entsprechender Quellcode:

ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk/vendor/customize/demo/example01/libsrc$  cat libmylib.cpp 
#include <iostream>

void libFunction() {
    
    
    std::cout << "This is from libmylib." << std::endl;
}
ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk/vendor/customize/demo/example01/libsrc$ cat libmylib.h
#pragma once

void libFunction();

  • Definieren Sie die Quelldateiliste: Sie können eine Variable zum Speichern der Quelldateiliste verwenden und dann in der Moduldefinition auf die Variable verweisen. Zum Beispiel:
# 构建myapp应用程序
include $(CLEAR_VARS)
LOCAL_MODULE := myapp
LOCAL_SRC_FILES := $(LOCAL_SRC_FILES_APP)
LOCAL_SHARED_LIBRARIES := libmylib
LOCAL_LDLIBS := -llog
LOCAL_CFLAGS := -Wall -Werror
include $(BUILD_EXECUTABLE)

Entsprechender Quellcode:

ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk/vendor/customize/demo/example01/src$ cat bar.cpp
#include "bar.h"
#include <iostream>

#include "../libsrc/libmylib.h"  // 添加这一行
void barFunction() {
    
    
    libFunction();
    std::cout << "Inside barFunction()" << std::endl;
    // TODO: Implement barFunction
}
ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk/vendor/customize/demo/example01/src$ cat bar.h
#ifndef BAR_H
#define BAR_H

void barFunction();

#endif // BAR_H
ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk/vendor/customize/demo/example01/src$ cat foo.cpp
#include "foo.h"
#include <iostream>

void fooFunction() {
    
    
    std::cout << "Inside fooFunction()" << std::endl;
    // TODO: Implement fooFunction
}
ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk/vendor/customize/demo/example01/src$ cat foo.h
#ifndef FOO_H
#define FOO_H

void fooFunction();

#endif // FOO_H
ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk/vendor/customize/demo/example01/src$ cat main.cpp 
#include "foo.h"
#include "bar.h"
#include <iostream>

int main() {
    
    
    std::cout << "Starting main()" << std::endl;
    fooFunction();
    barFunction();
    std::cout << "Ending main()" << std::endl;
    return 0;
}

5. Testen und Code

Vollständige Verzeichnisstruktur:

ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk/vendor/customize/demo/example01$ tree
.
├── Android.mk
├── libsrc
│   ├── libmylib.cpp
│   └── libmylib.h
└── src
    ├── bar.cpp
    ├── bar.h
    ├── foo.cpp
    ├── foo.h
    └── main.cpp

2 directories, 8 files

Fügen Sie hier eine Bildbeschreibung ein
Android.mk Vollständiger Code:

$(warning ====== 测试开始 ======)

# 使用:= 赋值操作符
file_name := source_file
# 打印file_name的值
$(warning file_name is $(file_name)) # 输出 file_name is source_file
# 改变file_name的值
file_name := header_file
# 再次打印file_name的值
$(warning file_name is $(file_name)) # 输出 file_name is header_file

# 使用:= 赋值操作符
file_extension := .txt
# 打印file_extension的值
$(warning file_extension is $(file_extension)) # 输出 file_extension is .txt
# 使用+= 追加赋值操作符
file_extension += .bak
# 再次打印file_extension的值
$(warning file_extension is $(file_extension)) # 输出 file_extension is .txt.bak

# 使用:= 赋值操作符
project_name := MyProject
# 打印project_name的值
$(warning project_name is $(project_name)) # 输出 project_name is MyProject
# 使用?= 条件赋值操作符
project_name ?= NewProject
# 再次打印project_name的值
$(warning project_name is $(project_name)) # 输出 project_name is MyProject  # 注意这里的结果没有改变,因为 project_name 已经被赋值过了

# 使用= 延迟赋值操作符
output_dir = build
# 打印output_dir的值
$(warning output_dir is $(output_dir)) # 输出 output_dir is build 
# 改变output_dir的值
output_dir = dist # 注意这里不是使用 := ,而是使用 =
# 再次打印output_dir的值
$(warning output_dir is $(output_dir)) # 输出 output_dir is dist 

# 使用:= 赋值操作符
config := debug
# 使用$(变量名) 引用变量的值
$(warning config is $(config)) # 输出 config is debug

# 使用:= 赋值操作符
config := release
# 使用${变量名} 引用变量的值
$(warning config is ${
     
     config}) # 输出 config is release
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 定义源文件列表
LOCAL_SRC_FILES := \
    src/main.cpp \
    src/foo.cpp \
    src/bar.cpp

# 定义一个可执行模块
LOCAL_MODULE := myapp 
# 明确指定这是一个可执行文件
LOCAL_MODULE_CLASS  := EXECUTABLES  
# 编译选项
LOCAL_CFLAGS := -Wall -Werror 
# 链接选项
LOCAL_LDLIBS := -llog 

# 引用源文件列表变量
LOCAL_SRC_FILES := $(LOCAL_SRC_FILES)

include $(BUILD_EXECUTABLE)
$(warning ====== 测试结束 ======)

all:
	@echo "测试example01结束!"

Versiegelungmmm vendor/customize/demo/example01 Siegel

[ 79% 221/278] including vendor/customize/demo/example01/Android.mk ...
vendor/customize/demo/example01/Android.mk:1: warning: ====== 测试开始 ======
vendor/customize/demo/example01/Android.mk:6: warning: file_name is source_file
vendor/customize/demo/example01/Android.mk:10: warning: file_name is header_file
vendor/customize/demo/example01/Android.mk:15: warning: file_extension is .txt
vendor/customize/demo/example01/Android.mk:19: warning: file_extension is .txt .bak
vendor/customize/demo/example01/Android.mk:24: warning: project_name is MyProject
vendor/customize/demo/example01/Android.mk:28: warning: project_name is MyProject
vendor/customize/demo/example01/Android.mk:33: warning: output_dir is build
vendor/customize/demo/example01/Android.mk:37: warning: output_dir is dist 
vendor/customize/demo/example01/Android.mk:42: warning: config is debug
vendor/customize/demo/example01/Android.mk:47: warning: config is release
vendor/customize/demo/example01/Android.mk:52: warning: VAR is hello1
vendor/customize/demo/example01/Android.mk:57: warning: VAR is hello2
vendor/customize/demo/example01/Android.mk:87: warning: ====== 测试结束 ======

Generationskonzept libmylib.soJapanisch myappTextelement

ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk$ cd out/target/product/rk3568_s$ find -name "libmylib*"
./obj_arm/SHARED_LIBRARIES/libmylib_intermediates
./obj_arm/SHARED_LIBRARIES/libmylib_intermediates/LINKED/libmylib.so
./obj_arm/SHARED_LIBRARIES/libmylib_intermediates/libsrc/libmylib.d
./obj_arm/SHARED_LIBRARIES/libmylib_intermediates/libsrc/libmylib.o
./obj_arm/SHARED_LIBRARIES/libmylib_intermediates/libmylib.so.strip.d
./obj_arm/SHARED_LIBRARIES/libmylib_intermediates/libmylib.so
./obj_arm/SHARED_LIBRARIES/libmylib_intermediates/libmylib.so.toc
./symbols/system/lib/libmylib.so
./symbols/system/lib64/libmylib.so
./system/lib/libmylib.so
./system/lib64/libmylib.so
./obj/SHARED_LIBRARIES/libmylib_intermediates
./obj/SHARED_LIBRARIES/libmylib_intermediates/LINKED/libmylib.so
./obj/SHARED_LIBRARIES/libmylib_intermediates/libsrc/libmylib.d
./obj/SHARED_LIBRARIES/libmylib_intermediates/libsrc/libmylib.o
./obj/SHARED_LIBRARIES/libmylib_intermediates/libmylib.so.strip.d
./obj/SHARED_LIBRARIES/libmylib_intermediates/libmylib.so
./obj/SHARED_LIBRARIES/libmylib_intermediates/libmylib.so.toc
ln28@ln28-pc:~/sourcecode/rk_android12.0_sdk$ cd out/target/product/rk3568_s$ find -name "myapp"
./symbols/system/bin/myapp
./system/bin/myapp
./obj/EXECUTABLES/myapp_intermediates/myapp
./obj/EXECUTABLES/myapp_intermediates/LINKED/myapp

Schieben Sie die Datei auf das Entwicklungsboard des Android-Systems und bereiten Sie sie zum Testen vor

C:\Users\Administrator>adb root
adbd is already running as root

C:\Users\Administrator>adb remount
remount succeeded

C:\Users\Administrator>adb push "Z:\rk_android12.0_sdk\out\target\product\rk3568_s\system\bin\myapp" /system/bin/
615 KB/s (11720 bytes in 0.018s)

C:\Users\Administrator>adb push "Z:\rk_android12.0_sdk\out\target\product\rk3568_s\system\lib\libmylib.so" /system/lib/
703 KB/s (5080 bytes in 0.007s)

C:\Users\Administrator>adb push "Z:\rk_android12.0_sdk\out\target\product\rk3568_s\system\lib64\libmylib.so" /system/lib
64/
1071 KB/s (11376 bytes in 0.010s)

Neue ReihenfolgemyappNeue Reihenfolge
Fügen Sie hier eine Bildbeschreibung ein

Zusammenfassen

In diesem Artikel wird die Verwendung von Zuweisungsvorgängen, Variablenverweisen und Funktionen in der Datei Android.mk sowie Beispiele für statische Bibliotheken und ausführbare Dateien vorgestellt. Durch die Verwendung dieser Konzepte können Sie die Variablen und Ausdrücke in der Android.mk-Datei flexibler steuern, um eine kundengerechte Funktionalität zu erreichen. Es gibt viele andere Variablen und Funktionen in der Android.mk-Datei, und ich werde sie weiterhin testen und hinzufügen, wenn ich Zeit habe.

Supongo que te gusta

Origin blog.csdn.net/SHH_1064994894/article/details/134073429
Recomendado
Clasificación