├── .gitignore ├── README.md └── install_android.py /.gitignore: -------------------------------------------------------------------------------- 1 | downloads 2 | output-* 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | These binaries contain Allegro pre-built for Android (armeabi-v7, arm64-v8a, x86, x86_64) and 2 | includes the following optional components: 3 | 4 | * freetype 5 | * flac 6 | * opus 7 | * vorbis 8 | * dumb 9 | * minimp3 10 | * physfs 11 | 12 | It does not include theora or freeimage at this point. 13 | 14 | To use the Allegro Android binaries from Android Studio 3: 15 | 16 | 1. Create a new Android Studio NDK project 17 | * Use "Start a new Android Studio project" from the welcome dialog or File->New from the menu 18 | * Select "Native C++" (Or in AS 3.2 check the "Include C++ support" checkbox on the first dialog) 19 | * Leave minimum SDK at 15 on the second dialog 20 | * Leave the C++ settings at their defaults 21 | * Click "Finish" 22 | 23 | Android Studio will create these files in your new project's folder (among others): 24 | 25 | * app/src/main/java/.../MainActivity.java 26 | * app/src/main/cpp/native-lib.cpp 27 | * app/build.gradle 28 | * app/src/main/cpp/CMakeLists.txt 29 | 30 | Run your project, just to make sure everything works right in your 31 | Android Studio installation and with your emulator and/or test device. 32 | The test program will display a text which comes from the native 33 | library. 34 | 35 | 2. In your app/build.gradle, inside of dependencies {}, add this: 36 | 37 | ``` 38 | implementation 'org.liballeg:allegro5-release:5.2.7.0' 39 | ``` 40 | 41 | In Android Studio in the "Android" view this file will be under "Gradle Scripts". 42 | 43 | (you can also use -debug instead of -release to use a debug version of Allegro) 44 | 45 | Sync your project (Tools-\>Android). This will make Android Studio download the .aar file from here: 46 | 47 | https://bintray.com/liballeg/maven 48 | 49 | If you prefer, you can remove the implementation/compile line and download the .aar 50 | yourself and open with any zip program. Then copy the .jar and .so files to where 51 | Android Studio can find them. 52 | 53 | Next install the Allegro headers: 54 | 55 | http://allegro5.org/android/5.2.7.0/allegro_jni_includes.zip 56 | 57 | or for the debug version: 58 | 59 | http://allegro5.org/android/5.2.7.0/allegro_jni_includes_debug.zip 60 | 61 | And unzip anywhere, for this example I will put it inside the project folder, so 62 | it will end up as app/src/main/allegro\_jni\_includes. 63 | 64 | 3. In your CMakeLists.txt (under External Build Files in Android Studio), add this to the end and sync: 65 | 66 | ``` 67 | set(NATIVE_LIB native-lib) 68 | set(JNI_FOLDER ${PROJECT_SOURCE_DIR}/../allegro_jni_includes) # or wherever you put it 69 | include(${JNI_FOLDER}/allegro.cmake) 70 | ``` 71 | 72 | 4. Modify app/src/main/java/.../MainActivity.java like this: 73 | (Keep your package name in the first line.) 74 | 75 | ``` 76 | import org.liballeg.android.AllegroActivity; 77 | public class MainActivity extends AllegroActivity { 78 | static { 79 | System.loadLibrary("allegro"); 80 | System.loadLibrary("allegro_primitives"); 81 | System.loadLibrary("allegro_image"); 82 | System.loadLibrary("allegro_font"); 83 | System.loadLibrary("allegro_ttf"); 84 | System.loadLibrary("allegro_audio"); 85 | System.loadLibrary("allegro_acodec"); 86 | System.loadLibrary("allegro_color"); 87 | } 88 | public MainActivity() { 89 | super("libnative-lib.so"); 90 | } 91 | } 92 | ``` 93 | (if you used the debug version above, the libraries will be called "allegro-debug" and so on) 94 | 95 | 5. Replace app/src/main/native-lib.cpp with your game's C/C++ code, using Allegro. Use app/CMakeLists.txt to list all of your C/C++ source files and extra dependencies. Hit Run in Android Studio and it will 96 | deploy and run your Allegro game on the emulator or actual devices. Build an .apk and upload it to the 97 | store and it will just work! 98 | 99 | To test that everything works you can initially just paste the following code into the existing native-lib.cpp. 100 | It creates a display then fades it from red to yellow every second. 101 | 102 | ```c 103 | #include 104 | 105 | int main(int argc, char **argv) { 106 | al_init(); 107 | auto display = al_create_display(0, 0); 108 | auto queue = al_create_event_queue(); 109 | auto timer = al_create_timer(1 / 60.0); 110 | auto redraw = true; 111 | al_register_event_source(queue, al_get_display_event_source(display)); 112 | al_register_event_source(queue, al_get_timer_event_source(timer)); 113 | al_start_timer(timer); 114 | while (true) { 115 | if (redraw) { 116 | al_clear_to_color(al_map_rgb_f(1, al_get_time() - (int)(al_get_time()), 0)); 117 | al_flip_display(); 118 | redraw = false; 119 | } 120 | ALLEGRO_EVENT event; 121 | al_wait_for_event(queue, &event); 122 | if (event.type == ALLEGRO_EVENT_TIMER) { 123 | redraw = true; 124 | } 125 | } 126 | return 0; 127 | } 128 | ``` 129 | 130 | 6. Fine-tuning 131 | 132 | * If you don't want to compile all the architectures for your game, you can do something like this in your app/build.gradle: 133 | ``` 134 | buildTypes { 135 | debug { 136 | ndk { 137 | abiFilters "armeabi-v7a"" 138 | } 139 | } 140 | } 141 | ``` 142 | * You will want to modify AndroidManifest.xml to have this attribute for the <activity> element or Allegro will crash: 143 | ``` 144 | android:configChanges="orientation|keyboardHidden|screenLayout|uiMode|screenSize" 145 | ``` 146 | 147 | * The way Allegro reads form the APK with al_android_set_apk_file_interface does not work for files which are recompressed inside of the APK. To prevent recompression add this to your app/build.gradle: 148 | ``` 149 | android { 150 | aaptOptions { 151 | noCompress "" 152 | } 153 | } 154 | ``` 155 | The "" means to not recompress any files, you can also provide a list of file extensions instead. 156 | -------------------------------------------------------------------------------- /install_android.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | import subprocess 4 | import os 5 | import shutil 6 | import urllib.request 7 | import tarfile 8 | import zipfile 9 | import glob 10 | import sys 11 | 12 | class Settings: 13 | jdk_url="http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.tar.gz" 14 | sdk_tgz_url = "https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip" 15 | ndk_zip_url = "https://dl.google.com/android/repository/android-ndk-r20-linux-x86_64.zip" 16 | 17 | min_api = { 18 | "armeabi-v7a" : "16", 19 | "x86" : "17", 20 | "x86_64" : "21", 21 | "arm64-v8a" : "21" 22 | } 23 | # see https://developer.android.com/ndk/guides/abis.html 24 | architectures = ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] 25 | freetype_url = "http://download.savannah.gnu.org/releases/freetype/freetype-2.7.tar.bz2" 26 | ogg_url = "http://downloads.xiph.org/releases/ogg/libogg-1.3.2.tar.xz" 27 | vorbis_url = "http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz" 28 | #png_url = "https://download.sourceforge.net/libpng/libpng-1.6.37.tar.xz" 29 | physfs_url = "https://icculus.org/physfs/downloads/physfs-3.0.2.tar.bz2" 30 | flac_url = "https://ftp.osuosl.org/pub/xiph/releases/flac/flac-1.3.2.tar.xz" 31 | opus_url = "https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz" 32 | opusfile_url = "https://archive.mozilla.org/pub/opus/opusfile-0.9.tar.gz" 33 | dumb_url = "https://github.com/kode54/dumb/archive/master.zip", "dumb.zip" 34 | minimp3_url = "https://github.com/lieff/minimp3/archive/master.zip", "minimp3.zip" 35 | #theora_url = "https://git.xiph.org/?p=theora.git;a=snapshot;h=HEAD;sf=tgz", "theora.tar.gz" 36 | build_tools_version = "28.0.0" 37 | 38 | s = Settings() 39 | 40 | def main(): 41 | global args 42 | path = os.getcwd() 43 | p = argparse.ArgumentParser() 44 | p.add_argument("-i", "--install", action = "store_true") 45 | p.add_argument("-b", "--build", action = "store_true") 46 | p.add_argument("-p", "--package", action = "store_true") 47 | p.add_argument("-d", "--dist", action = "store_true") 48 | p.add_argument("-a", "--allegro", help = "path to allegro") 49 | p.add_argument("-P", "--path", help = "path to install to, by default current directory") 50 | p.add_argument("-A", "--arch", help = "comma separated list of architectures, by default all are built: " + (", ".join(Settings.architectures))) 51 | p.add_argument("-D", "--debug", action = "store_true", help = "build debug libraries") 52 | p.add_argument("-E", "--extra", help = "extra version suffix") 53 | 54 | args = p.parse_args() 55 | if not args.path: 56 | args.path = os.getcwd() 57 | s.log = open(args.path + "/install_android.log", "w") 58 | 59 | if args.arch: 60 | archs = args.arch.split(",") 61 | for a in archs: 62 | if a not in s.architectures: 63 | sys.stderr.write("Unknown architecture " + a + "\n") 64 | sys.exit(-1) 65 | s.architectures = archs 66 | s.sdk = download_and_unpack(s.sdk_tgz_url, "tools") 67 | s.ndk = download_and_unpack(s.ndk_zip_url) 68 | setup_jdk() 69 | 70 | if args.install: 71 | install_sdk() 72 | install_ndk() 73 | install_freetype() 74 | install_ogg() 75 | install_vorbis() 76 | # not supported on Android right now, always uses native png() 77 | install_physfs() 78 | install_flac() 79 | install_opus() 80 | install_opusfile() 81 | install_dumb() 82 | install_minimp3() 83 | # can't get it to compile for android install_theora() 84 | 85 | if args.build or args.package: 86 | if not args.allegro: 87 | print("Need -a option to build/package!") 88 | return 89 | 90 | os.chdir(path) 91 | args.allegro = os.path.abspath(args.allegro) 92 | print("Allegro found at", args.allegro) 93 | 94 | parse_version() 95 | if not s.version: 96 | print("Cannot find version!") 97 | return 98 | 99 | if args.build: 100 | build_allegro() 101 | 102 | if args.package: 103 | print("Packaging version", s.version) 104 | build_aar() 105 | 106 | def parse_version(): 107 | x = [ 108 | "#define ALLEGRO_VERSION ", 109 | "#define ALLEGRO_SUB_VERSION ", 110 | "#define ALLEGRO_WIP_VERSION ", 111 | "#define ALLEGRO_RELEASE_NUMBER "] 112 | v = [] 113 | for row in open(args.allegro + "/include/allegro5/base.h"): 114 | for i in range(4): 115 | if row.startswith(x[i]): 116 | v.append(row[len(x[i]):].strip(" \"\n")) 117 | s.version = ".".join(v) 118 | if args.extra: 119 | s.version += args.extra 120 | 121 | def com(*args, input = None): 122 | args = [x for x in args if x is not None] 123 | print(" ".join(args)) 124 | s.log.write(" ".join(args) + "\n") 125 | try: 126 | r = subprocess.run(args, check = True, input = input, 127 | env = os.environ, 128 | stdout = subprocess.PIPE, stderr = subprocess.STDOUT) 129 | except subprocess.CalledProcessError as e: 130 | r = e 131 | sys.stderr.write(" ______\n") 132 | sys.stderr.write("/FAILED\\\n") 133 | sys.stderr.write("´`´`´`´`\n") 134 | s.log.write("FAILED\n") 135 | if r.stdout: 136 | s.log.write(r.stdout.decode("utf8") + "\n") 137 | 138 | def makedirs(name): 139 | s.log.write("mkdir -p " + name + "\n") 140 | print("mkdir -p " + name) 141 | os.makedirs(name, exist_ok = True) 142 | 143 | def chdir(name): 144 | s.log.write("cd " + name + "\n") 145 | print("cd " + name) 146 | os.chdir(name) 147 | 148 | def write(name, contents, placeholders = {}): 149 | print("create", name) 150 | contents = contents.replace("{", "{{") 151 | contents = contents.replace("}", "}}") 152 | contents = contents.replace("«", "{") 153 | contents = contents.replace("»", "}") 154 | contents = contents.format(**placeholders) 155 | open(name, "w").write(contents.strip() + "\n") 156 | 157 | def copy(source, destination): 158 | com("cp", "-r", source, destination) 159 | 160 | def replace(name, what, whatwith): 161 | print("edit", name) 162 | x = open(name, "r").read() 163 | x = x.replace(what, whatwith) 164 | open(name, "w").write(x) 165 | 166 | def rm(pattern): 167 | for f in glob.glob(pattern): 168 | os.unlink(f) 169 | 170 | def download(url, path): 171 | if not os.path.exists(path): 172 | print("Downloading", url) 173 | 174 | req = urllib.request.Request(url) 175 | req.add_header("Cookie", "oraclelicense=accept-securebackup-cookie") 176 | r = urllib.request.urlopen(req) 177 | with open(path + ".part", "wb") as f: 178 | f.write(r.read()) 179 | os.rename(path + ".part", path) 180 | 181 | def download_and_unpack(url, sub_folder = None): 182 | if type(url) is tuple: 183 | url, dest = url 184 | else: 185 | slash = url.rfind("/") 186 | dest = url[slash + 1:] 187 | print("Checking", url) 188 | os.makedirs(args.path + "/downloads", exist_ok = True) 189 | name = args.path + "/downloads/" + dest 190 | download(url, name) 191 | 192 | dot = name.rfind(".") 193 | folder = name[:dot] 194 | if folder.endswith(".tar"): 195 | folder = folder[:-4] 196 | target_folder = folder 197 | if sub_folder: 198 | target_folder += "/" + sub_folder 199 | if not os.path.exists(target_folder): 200 | shutil.rmtree(target_folder + ".part", ignore_errors = True) 201 | os.makedirs(target_folder + ".part", exist_ok = True) 202 | 203 | print("Unpacking", name) 204 | if zipfile.is_zipfile(name): 205 | # doesn't preserve permissions in some python versions 206 | #with zipfile.ZipFile(name) as z: 207 | # z.extractall(folder + ".part") 208 | com("unzip", "-q", "-d", target_folder + ".part", name) 209 | else: 210 | tarfile.open(name).extractall(target_folder + ".part") 211 | 212 | for sub in glob.glob(target_folder + ".part/*"): 213 | if os.path.isdir(sub): 214 | shutil.move(sub, folder) 215 | break 216 | os.rmdir(target_folder + ".part") 217 | 218 | return folder 219 | 220 | def setup_jdk(): 221 | s.jdk = download_and_unpack(s.jdk_url) 222 | set_var("JAVA_HOME", s.jdk + "/jre") 223 | 224 | def install_sdk(): 225 | components = [ 226 | "platform-tools", 227 | "build-tools;" + s.build_tools_version, 228 | "platforms;android-28" 229 | ] 230 | sdkmanager = s.sdk + "/tools/bin/sdkmanager" 231 | for component in components: 232 | com(sdkmanager, component, "--sdk_root=" + s.sdk, input = b"y\n") 233 | 234 | def install_ndk(): 235 | for arch in s.architectures: 236 | install = args.path + "output-" + arch.replace(" ", "_") 237 | if os.path.exists(install): 238 | continue 239 | print("Creating installation for", arch) 240 | com("mkdir", install) 241 | 242 | def set_var(key, val): 243 | print(key + "=" + val) 244 | os.environ[key] = val 245 | 246 | def add_path(val): 247 | print("PATH=" + val + ":${PATH}") 248 | os.environ["PATH"] = val + ":" + os.environ["PATH"] 249 | 250 | def backup_path(): 251 | s.backup_path = os.environ["PATH"] 252 | 253 | def restore_path(): 254 | os.environ["PATH"] = s.backup_path 255 | 256 | # see https://developer.android.com/ndk/guides/other_build_systems 257 | def setup_host(arch): 258 | toolchain = s.ndk + "/toolchains/llvm/prebuilt/linux-x86_64" # this is the host architecture, not what we are building 259 | 260 | host2 = None 261 | if arch == "x86": 262 | host = "i686-linux-android" 263 | if arch == "x86_64": 264 | host = arch + "-linux-android" 265 | if arch == "armeabi-v7a": 266 | host = "arm-linux-androideabi" 267 | host2 = "armv7a-linux-androideabi" 268 | if arch == "arm64-v8a": 269 | host = "aarch64-linux-android" 270 | if host2 is None: 271 | host2 = host 272 | 273 | minsdk = s.min_api[arch] 274 | install = args.path + "/output-" + arch.replace(" ", "_") 275 | 276 | set_var("ANDROID_NDK_ROOT", s.ndk) 277 | set_var("ANDROID_HOME", s.sdk) 278 | set_var("ANDROID_NDK_TOOLCHAIN_ROOT", toolchain) 279 | set_var("PKG_CONFIG_LIBDIR", toolchain + "/lib/pkgconfig") 280 | set_var("PKG_CONFIG_PATH", install + "/lib/pkgconfig") 281 | set_var("AR", toolchain + "/bin/" + host + "-ar") 282 | set_var("AS", toolchain + "/bin/" + host + "-as") 283 | set_var("LD", toolchain + "/bin/" + host + "-ld") 284 | set_var("RANLIB", toolchain + "/bin/" + host + "-ranlib") 285 | set_var("STRIP", toolchain + "/bin/" + host + "-strip") 286 | set_var("CC", toolchain + "/bin/" + host2 + minsdk + "-clang") 287 | set_var("CXX", toolchain + "/bin/" + host2 + minsdk + "-clang++") 288 | set_var("CFLAGS", "-fPIC") 289 | backup_path() 290 | add_path(s.ndk) 291 | add_path(s.sdk) 292 | add_path(toolchain + "/bin") 293 | 294 | #com(host + "-gcc", "-v") 295 | 296 | return host, install 297 | 298 | def build_architectures(path, configure): 299 | slash = path.rfind("/") 300 | name = path[slash + 1:] 301 | for arch in s.architectures: 302 | print("Building", path, "for", arch) 303 | host, install = setup_host(arch) 304 | 305 | destination = install + "/build/" + name 306 | if not os.path.exists(destination): 307 | shutil.copytree(path, destination) 308 | chdir(destination) 309 | 310 | configure(arch, host, install) 311 | restore_path() 312 | 313 | def configure_f(*extras): 314 | def f(arch, host, prefix): 315 | if not os.path.exists("configure"): 316 | com("./autogen.sh") 317 | com("./configure", "--host=" + host, "--prefix=" + prefix, *extras) 318 | com("make", "-j4") 319 | com("make", "install") 320 | return f 321 | 322 | def cmake_f(*extras): 323 | cmake_toolchain = s.ndk + "/build/cmake/android.toolchain.cmake" 324 | def f(arch, host, prefix): 325 | com("cmake", "-DCMAKE_TOOLCHAIN_FILE=" + cmake_toolchain, 326 | "-DANDROID_ABI=" + arch, 327 | "-DCMAKE_INSTALL_PREFIX=" + prefix, 328 | *extras) 329 | com("make", "-j4") 330 | com("make", "install") 331 | return f 332 | 333 | def install_freetype(): 334 | ft_orig = download_and_unpack(s.freetype_url) 335 | build_architectures(ft_orig, configure_f("--without-png", "--without-harfbuzz", 336 | "--with-zlib=no", 337 | "--with-bzip2=no")) 338 | 339 | def install_ogg(): 340 | ogg_orig = download_and_unpack(s.ogg_url) 341 | build_architectures(ogg_orig, configure_f()) 342 | 343 | def install_vorbis(): 344 | vorbis_orig = download_and_unpack(s.vorbis_url) 345 | 346 | # need to patch libvorbis 1.3.5 to work with clang on i386 347 | print("Patching libvorbis 1.3.5") 348 | b = open(vorbis_orig + "/configure").read() 349 | b = b.replace("-mno-ieee-fp", "") 350 | open(vorbis_orig + "/configure", "w").write(b) 351 | 352 | build_architectures(vorbis_orig, configure_f()) 353 | 354 | def install_png(): 355 | png_orig = download_and_unpack(s.png_url) 356 | build_architectures(png_orig, configure_f()) 357 | 358 | def install_physfs(): 359 | physfs_orig = download_and_unpack(s.physfs_url) 360 | build_architectures(physfs_orig, cmake_f("-DPHYSFS_BUILD_SHARED=OFF")) 361 | 362 | def install_flac(): 363 | flac_orig = download_and_unpack(s.flac_url) 364 | build_architectures(flac_orig, configure_f( 365 | "--disable-cpplibs", "--disable-shared", "--enable-static", "--disable-ogg")) 366 | 367 | def install_opus(): 368 | opus_orig = download_and_unpack(s.opus_url) 369 | build_architectures(opus_orig, configure_f( 370 | "--disable-shared", "--enable-static")) 371 | 372 | def install_opusfile(): 373 | orig = download_and_unpack(s.opusfile_url) 374 | build_architectures(orig, configure_f( 375 | "--disable-shared", "--enable-static")) 376 | 377 | def install_dumb(): 378 | dumb_orig = download_and_unpack(s.dumb_url) 379 | build_architectures(dumb_orig, cmake_f("-DBUILD_EXAMPLES=OFF", "-DBUILD_ALLEGRO4=OFF")) 380 | 381 | def install_minimp3(): 382 | orig = download_and_unpack(s.minimp3_url) 383 | def f(arch, host, install): 384 | com("cp", "minimp3.h", install + "/include/") 385 | com("cp", "minimp3_ex.h", install + "/include/") 386 | build_architectures(orig, f) 387 | 388 | def install_theora(): 389 | orig = download_and_unpack(s.theora_url) 390 | build_architectures(orig, configure_f( 391 | "--disable-shared", "--enable-static")) 392 | 393 | def build_allegro(): 394 | for arch in s.architectures: 395 | print("Building Allegro for", arch) 396 | 397 | host, install = setup_host(arch) 398 | build = install + "/build/allegro" 399 | if args.debug: 400 | build += "-debug" 401 | shutil.rmtree(build, ignore_errors = True) 402 | makedirs(build) 403 | chdir(build) 404 | 405 | cmake_toolchain = s.ndk + "/build/cmake/android.toolchain.cmake" 406 | 407 | extra = None 408 | if arch == "armeabi": 409 | extra = "-DWANT_ANDROID_LEGACY=on" 410 | 411 | debug = "Release" 412 | if args.debug: 413 | debug = "Debug" 414 | include = install + "/include" 415 | com("cmake", args.allegro, "-DCMAKE_TOOLCHAIN_FILE=" + cmake_toolchain, 416 | "-DANDROID_ABI=" + arch, 417 | "-DCMAKE_BUILD_TYPE=" + debug, 418 | "-DANDROID_TARGET=android-26", 419 | "-DCMAKE_INSTALL_PREFIX=" + install, 420 | extra, 421 | "-DWANT_DEMO=off", 422 | "-DWANT_EXAMPLES=off", 423 | "-DWANT_TESTS=off", 424 | "-DWANT_DOCS=off", 425 | "-DPKG_CONFIG_EXECUTABLE=/usr/bin/pkg-config", 426 | "-DOGG_LIBRARY=" + install + "/lib/libogg.a", 427 | "-DOGG_INCLUDE_DIR=" + include, 428 | "-DVORBIS_LIBRARY=" + install + "/lib/libvorbis.a", 429 | "-DVORBIS_INCLUDE_DIR=" + include, 430 | "-DVORBISFILE_LIBRARY=" + install + "/lib/libvorbisfile.a", 431 | "-DSUPPORT_VORBIS=true", 432 | "-DFREETYPE_LIBRARY=" + install + "/lib/libfreetype.a", 433 | "-DFREETYPE_INCLUDE_DIRS=" + install + "/include;" + install + "/include/freetype2", 434 | #"-DPNG_INCLUDE_DIR=" + install + "/include", 435 | #"-DPNG_LIBRARY=" + install + "/lib/libpng.a", 436 | "-DFLAC_LIBRARY=" + install + "/lib/libFLAC.a", 437 | "-DFLAC_INCLUDE_DIR=" + include, 438 | "-DPHYSFS_LIBRARY=" + install + "/lib/libphysfs.a", 439 | "-DPHYSFS_INCLUDE_DIR=" + include, 440 | "-DOPUS_LIBRARY=" + install + "/lib/libopus.a", 441 | "-DOPUS_INCLUDE_DIR=" + include + "/opus", 442 | "-DOPUSFILE_LIBRARY=" + install + "/lib/libopusfile.a", 443 | "-DDUMB_LIBRARY=" + install + "/lib/libdumb.a", 444 | "-DDUMB_INCLUDE_DIR=" + include, 445 | "-DMINIMP3_INCLUDE_DIRS=" + include, 446 | #"-DTHEORA_LIBRARY=" + install + "/lib/libtheora.a", 447 | #"-DTHEORA_INCLUDE_DIR=" + include, 448 | ) 449 | 450 | com("make", "-j4", "VERBOSE=1") 451 | # Get rid of previously installed files, so for example we get 452 | # no debug libaries in a release build. 453 | rm(install + "/lib/liballegro*") 454 | com("make", "install") 455 | 456 | restore_path() 457 | 458 | def build_aar(): 459 | shutil.rmtree(args.path + "/gradle_project", ignore_errors = True) 460 | copy(args.allegro + "/android/gradle_project", args.path + "/gradle_project") 461 | 462 | allegro5 = args.path + "/gradle_project/allegro" 463 | includes = args.path + "/gradle_project/allegro_jni_includes" 464 | if args.debug: 465 | includes += "_debug" 466 | 467 | for arch in s.architectures: 468 | install = args.path + "/output-" + arch.replace(" ", "_") 469 | makedirs(allegro5 + "/src/main/jniLibs/" + arch) 470 | for so in glob.glob(install + "/lib/liballeg*"): 471 | copy(so, allegro5 + "/src/main/jniLibs/" + arch + "/") 472 | 473 | makedirs(includes + "/jniIncludes") 474 | # Note: the Allegro headers are the same for all architectures, so just copy from the first one 475 | copy(args.path + "/output-" + s.architectures[0] + "/include/allegro5", includes + "/jniIncludes/") 476 | copy(allegro5 + "/src/main/jniLibs", includes) 477 | 478 | write(includes + "/allegro.cmake", 479 | """ 480 | get_filename_component(ABI ${CMAKE_BINARY_DIR} NAME) 481 | set(base ${CMAKE_CURRENT_LIST_DIR}) 482 | 483 | macro(standard_library NAME) 484 | string(TOUPPER ${NAME} UNAME) 485 | find_library(LIB_${UNAME} ${NAME}) 486 | target_link_libraries(${NATIVE_LIB} ${LIB_${UNAME}}) 487 | endmacro() 488 | 489 | macro(allegro_library NAME) 490 | string(TOUPPER ${NAME} UNAME) 491 | set(path ${JNI_FOLDER}/jniLibs/${ABI}/lib${NAME}) 492 | if(EXISTS "${path}-debug.so") 493 | set(LIB_${UNAME} ${path}-debug.so) 494 | elseif(EXISTS "${path}.so") 495 | set(LIB_${UNAME} ${path}.so) 496 | else() 497 | message(SEND_ERROR "${path}.so does not exist") 498 | endif() 499 | target_link_libraries(${NATIVE_LIB} ${LIB_${UNAME}}) 500 | endmacro() 501 | 502 | include_directories(${JNI_FOLDER}/jniIncludes) 503 | allegro_library(allegro) 504 | allegro_library(allegro_acodec) 505 | allegro_library(allegro_audio) 506 | allegro_library(allegro_color) 507 | allegro_library(allegro_font) 508 | allegro_library(allegro_image) 509 | allegro_library(allegro_primitives) 510 | allegro_library(allegro_ttf) 511 | standard_library(m) 512 | standard_library(z) 513 | standard_library(log) 514 | standard_library(GLESv2) 515 | """) 516 | write(allegro5 + "/src/main/AndroidManifest.xml", """ 517 | 519 | 520 | """.lstrip()) 521 | write(args.path + "/gradle_project/gradle.properties", """ 522 | org.gradle.java.home={} 523 | """.format(s.jdk)) 524 | write(args.path + "/gradle_project/local.properties", """ 525 | ndk.dir={} 526 | sdk.dir={} 527 | """.format(s.ndk, s.sdk)) 528 | write(args.path + "/gradle_project/build.gradle", """ 529 | buildscript { 530 | repositories { 531 | google() 532 | jcenter() 533 | } 534 | dependencies { 535 | classpath 'com.android.tools.build:gradle:3.1.0' 536 | } 537 | } 538 | """) 539 | debug = "debug" if args.debug else "release" 540 | write(allegro5 + "/build.gradle", """ 541 | plugins { 542 | id "com.jfrog.bintray" version "1.7" 543 | id "com.github.dcendents.android-maven" version "1.5" 544 | } 545 | apply plugin: 'com.android.library' 546 | 547 | android { 548 | compileSdkVersion 28 549 | defaultConfig { 550 | minSdkVersion 15 551 | targetSdkVersion 28 552 | versionCode 1 553 | versionName "«version»" 554 | } 555 | } 556 | repositories { 557 | google() 558 | jcenter() 559 | } 560 | dependencies { 561 | implementation 'com.android.support:appcompat-v7:28.0.0' 562 | } 563 | archivesBaseName = "allegro5-«debug»" 564 | group = "org.liballeg" 565 | version = "«version»" 566 | task sourcesJar(type: Jar) { 567 | from android.sourceSets.main.java.srcDirs 568 | classifier = 'sources' 569 | } 570 | task javadoc(type: Javadoc) { 571 | source = android.sourceSets.main.java.srcDirs 572 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 573 | } 574 | task javadocJar(type: Jar, dependsOn: javadoc) { 575 | classifier = 'javadoc' 576 | from javadoc.destinationDir 577 | } 578 | 579 | artifacts { 580 | archives javadocJar 581 | archives sourcesJar 582 | } 583 | 584 | install { 585 | repositories.mavenInstaller { 586 | pom.project { 587 | name 'allegro5-«debug»' 588 | description 'Allegro for Android' 589 | url 'http://liballeg.org' 590 | inceptionYear '1995' 591 | artifactId "allegro5-«debug»" 592 | 593 | packaging 'aar' 594 | groupId 'org.liballeg' 595 | version '«version»' 596 | 597 | licenses { 598 | license { 599 | name 'zlib' 600 | url 'http://liballeg.org/license.html' 601 | distribution 'repo' 602 | } 603 | } 604 | scm { 605 | connection 'https://github.com/liballeg/allegro5.git' 606 | url 'https://github.com/liballeg/allegro5' 607 | 608 | } 609 | developers { 610 | developer { 611 | name 'Allegro Developers' 612 | } 613 | } 614 | } 615 | } 616 | } 617 | 618 | Properties properties = new Properties() 619 | File f = "../bintray.properties" as File 620 | properties.load(f.newDataInputStream()) 621 | // needs a file bintray.properties with this inside: 622 | // bintray.user = 623 | // bintray.key = 624 | 625 | bintray { 626 | user = properties.getProperty("bintray.user") 627 | key = properties.getProperty("bintray.key") 628 | configurations = ['archives'] 629 | pkg { 630 | repo = 'maven' 631 | name = 'allegro5-«debug»' 632 | userOrg = 'liballeg' 633 | licenses = ['zlib'] 634 | vcsUrl = 'https://github.com/liballeg/allegro5.git' 635 | version { 636 | name = '«version»' 637 | } 638 | publish = true 639 | } 640 | } 641 | """, {"version" : s.version, "debug" : debug, "build_tools_version" : s.build_tools_version}) 642 | write(args.path + "/gradle_project/settings.gradle", "include ':allegro'") 643 | 644 | chdir(args.path + "/gradle_project") 645 | com("zip", "-r", includes + ".zip", includes) 646 | com("./gradlew", "assembleDebug" if args.debug else "assembleRelease") 647 | 648 | if args.dist: 649 | com("./gradlew", "bintrayUpload") 650 | makedirs("/var/www/allegro5.org/android/" + s.version) 651 | copy(includes + ".zip", "/var/www/allegro5.org/android/" + s.version) 652 | 653 | if __name__ == "__main__": 654 | main() 655 | --------------------------------------------------------------------------------