Lors du développement avec le NDK Android, la configuration du fichier Android.mk est une étape indispensable. L'un des aspects les plus fastidieux concerne la variable LOCAL_SRC_FILES, qui doit lister tous les fichiers sources C/C++ à compiler. Pour les projets d'envergure, énumérer chaque fichier manuellement est une source d'erreurs et de perte de temps.
Imaginons l'arborescence suivante pour un projet JNI :
jni/
├── main.cpp
├── platform_check.cpp
├── Android.mk
├── Application.mk
└── engine/
├── core.cpp
├── renderer.cpp
└── utils/
├── logger.cpp
└── math.cpp
Une approche classique consisterait à écrire :
LOCAL_SRC_FILES := main.cpp \
platform_check.cpp \
engine/core.cpp \
engine/renderer.cpp \
engine/utils/logger.cpp \
engine/utils/math.cpp
Cette méthode n'est pas évolutive. Voici plusieurs techniques pour automatiser ce processus en utilisant les fonctionnalités de GNU Make.
Méthode 1 : Utilisation des jokers (Wildcards) pour un répertoire plat
Si vos fichiers sont regroupés dans quelques répertoires spécifiques sans une arborescence trop profonde, vous pouvez utiliser la fonction wildcard.
# Capture des fichiers dans le dossier racine et les sous-dossiers immédiats
FICHIERS_BRUTS := $(wildcard $(LOCAL_PATH)/*.cpp)
FICHIERS_BRUTS += $(wildcard $(LOCAL_PATH)/engine/*.cpp)
# Nettoyage des chemins pour les rendre relatifs à LOCAL_PATH
LOCAL_SRC_FILES := $(FICHIERS_BRUTS:$(LOCAL_PATH)/%=%)
Ici, $(LOCAL_PATH)/%=% est une substiuttion de motif qui supprime le préfixe du chemin absolu pour ne conserver que le chemin relatif requis par le NDK.
Méthode 2 : Recherche récursive via Shell
Pour inclure automatiquement tous les fichiers .cpp présents dans un répertoire et tous ses sous-répertoires, l'utilisation de la commande find via la fonction shell est la solution la plus efficace.
# Définition du point d'entrée de la recherche
DOSSIER_SOURCE := $(LOCAL_PATH)
# Exécution de la commande find pour lister tous les fichiers
TOUS_LES_DOCUMENTS := $(shell find $(DOSSIER_SOURCE) -type f)
# Filtrage pour ne garder que les fichiers C++
LISTE_CPP := $(filter %.cpp, $(TOUS_LES_DOCUMENTS))
# Conversion en chemins relatifs
LOCAL_SRC_FILES := $(LISTE_CPP:$(LOCAL_PATH)/%=%)
Cette approche permet d'ajouter de nouveaux fichiers ou de créer des sous-dossiers sans jamais avoir à modifier le fichier Android.mk.
Méthode 3 : Gestion multi-extensions et répertoires multiples
Dans un environnement de production, il est fréquent de devoir gérer plusieurs extensions (.c, .cpp, .cc) et de compiler des sources situées en dehors du dossier jni/ (par exemple, des classes partagées avec une autre plateforme).
# 1. Lister les dossiers racines contenant du code source
CHEMINS_SOURCES := $(LOCAL_PATH) \
$(LOCAL_PATH)/../../Classes \
$(LOCAL_PATH)/../external/lib_xxx
# 2. Définir les extensions de fichiers à traiter
EXTENSIONS_RECHERCHEES := %.cpp %.c %.cc
# 3. Collecter tous les fichiers de manière récursive dans chaque dossier
COLLECTE_GLOBALE := $(foreach dossier, $(CHEMINS_SOURCES), $(shell find $(dossier) -type f))
# 4. Appliquer le filtre d'extension
SOURCES_FILTREES := $(filter $(EXTENSIONS_RECHERCHEES), $(COLLECTE_GLOBALE))
# 5. Normaliser les chemins pour Android.mk
# Nous utilisons patsubst pour transformer les chemins absolus en relatifs
LOCAL_SRC_FILES := $(patsubst $(LOCAL_PATH)/%, %, $(SOURCES_FILTREES))
Quelques explications sur les fonctiosn utilisées :
foreach: Parcourt chaque dossier défini dansCHEMINS_SOURCES.shell find: Localise physiquement les fichiers sur le disque.filter: Ne conserve que les éléments correspondant aux motifs d'extensions.patsubst: Assure que les fichiers situés dans le répertoire local n'ont pas de chemin absolu, ce qui est crucial pour la portabilité du build NDK.