Forráskód Böngészése

Really bodgy android packing system for `odin build`

gingerBill 5 hónapja
szülő
commit
45ecafd7b1
3 módosított fájl, 202 hozzáadás és 4 törlés
  1. 33 3
      src/build_settings.cpp
  2. 147 1
      src/linker.cpp
  3. 22 0
      src/main.cpp

+ 33 - 3
src/build_settings.cpp

@@ -543,8 +543,9 @@ struct BuildContext {
 	String ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL;
 	String ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT;
 
-	String ANDROID_JAR_SIGNER;
+	String ODIN_ANDROID_JAR_SIGNER;
 	String android_keystore;
+	String android_keystore_alias;
 	String android_manifest;
 };
 
@@ -1816,6 +1817,32 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
 		bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB, make_string_c(buf));
 
 		bc->ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/"));
+
+
+		bc->ODIN_ANDROID_JAR_SIGNER = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_JAR_SIGNER", permanent_allocator())), NIX_SEPARATOR_STRING);
+		if (bc->build_mode == BuildMode_Executable) {
+			if (bc->ODIN_ANDROID_SDK.len == 0)  {
+				gb_printf_err("Error: ODIN_ANDROID_SDK not set, which is required for -build-mode:executable for -subtarget:android");
+				gb_exit(1);
+			}
+			if (bc->ODIN_ANDROID_JAR_SIGNER.len == 0) {
+				gb_printf_err("Error: ODIN_ANDROID_JAR_SIGNER not set, which is required for -build-mode:executable for -subtarget:android");
+				gb_exit(1);
+			}
+			if (bc->android_keystore.len == 0) {
+				gb_printf_err("Error: -android-keystore:<string> has not been set\n");
+				gb_exit(1);
+			}
+			if (bc->android_keystore_alias.len == 0) {
+				gb_printf_err("Error: -android-keystore_alias:<string> has not been set\n");
+				gb_exit(1);
+			}
+			if (bc->android_manifest.len == 0) {
+				gb_printf_err("Error: -android-manifest:<string> has not been set\n");
+				gb_exit(1);
+			}
+		}
+
 	}
 
 	if (!bc->custom_optimization_level) {
@@ -1862,16 +1889,18 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
 
 	if (subtarget == Subtarget_Android) {
 		switch (build_context.build_mode) {
+		case BuildMode_Executable:
 		case BuildMode_DynamicLibrary:
 		case BuildMode_Object:
 		case BuildMode_Assembly:
 		case BuildMode_LLVM_IR:
 			break;
-		case BuildMode_Executable:
+		default:
 		case BuildMode_StaticLibrary:
 			if ((build_context.command_kind & Command__does_build) != 0) {
 				gb_printf_err("Unsupported -build-mode for -subtarget:android\n");
 				gb_printf_err("\tCurrently only supporting: \n");
+				gb_printf_err("\t\texe\n");
 				gb_printf_err("\t\tshared\n");
 				gb_printf_err("\t\tobject\n");
 				gb_printf_err("\t\tassembly\n");
@@ -2080,7 +2109,8 @@ gb_internal bool init_build_paths(String init_filename) {
 		String const single_file_extension = str_lit(".odin");
 
 		if (selected_subtarget == Subtarget_Android) {
-			output_extension = STR_LIT("bin");
+			// NOTE(bill): It's always shared!
+			output_extension = STR_LIT("so");
 		} else if (build_context.metrics.os == TargetOs_windows) {
 			output_extension = STR_LIT("exe");
 		} else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {

+ 147 - 1
src/linker.cpp

@@ -742,7 +742,9 @@ try_cross_linking:;
 					link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' ");
 					link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
 				}
-
+			} else if (is_android) {
+				// Always shared even in android!
+				link_settings = gb_string_appendc(link_settings, "-shared ");
 			}
 
 			if (build_context.build_mode == BuildMode_Executable && build_context.reloc_mode == RelocMode_PIC) {
@@ -866,6 +868,150 @@ try_cross_linking:;
 					return result;
 				}
 			}
+			if (is_android && build_context.build_mode == BuildMode_Executable) {
+				String android_sdk_build_tools = concatenate3_strings(temporary_allocator(),
+					build_context.ODIN_ANDROID_SDK, str_lit("build-tools"), NIX_SEPARATOR_STRING);
+
+				Array<FileInfo> list = {};
+				ReadDirectoryError rd_err = read_directory(android_sdk_build_tools, &list);
+				defer (array_free(&list));
+
+				switch (rd_err) {
+				case ReadDirectory_InvalidPath:
+					gb_printf_err("Invalid path: %.*s\n", LIT(android_sdk_build_tools));
+					return 1;
+				case ReadDirectory_NotExists:
+					gb_printf_err("Path does not exist: %.*s\n", LIT(android_sdk_build_tools));
+					return 1;
+				case ReadDirectory_Permission:
+					gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools));
+					return 1;
+				case ReadDirectory_NotDir:
+					gb_printf_err("Expected a directory for a package, got a file: %.*s\n", LIT(android_sdk_build_tools));
+					return 1;
+				case ReadDirectory_Empty:
+					gb_printf_err("Empty directory: %.*s\n", LIT(android_sdk_build_tools));
+					return 1;
+				case ReadDirectory_Unknown:
+					gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools));
+					return 1;
+				}
+
+				auto possible_valid_dirs = array_make<FileInfo>(heap_allocator(), 0, list.count);
+				defer (array_free(&possible_valid_dirs));
+
+
+				for (FileInfo fi : list) if (fi.is_dir) {
+					bool all_numbers = true;
+					for (isize i = 0; i < fi.name.len; i++) {
+						u8 c = fi.name[i];
+						if ('0' <= c && c <= '9') {
+							// true
+						} else if (i == 0) {
+							all_numbers = false;
+						} else if (c == '.') {
+							break;
+						} else {
+							all_numbers = false;
+						}
+					}
+
+					if (all_numbers) {
+						array_add(&possible_valid_dirs, fi);
+					}
+				}
+
+				if (possible_valid_dirs.count == 0) {
+					gb_printf_err("Unable to find any Android SDK/API Level in %.*s\n", LIT(android_sdk_build_tools));
+					return 1;
+				}
+
+				int *dir_numbers = gb_alloc_array(temporary_allocator(), int, possible_valid_dirs.count);
+
+				char buf[1024] = {};
+				for_array(i, possible_valid_dirs) {
+					FileInfo fi = possible_valid_dirs[i];
+					isize n = gb_min(gb_size_of(buf)-1, fi.name.len);
+					memcpy(buf, fi.name.text, n);
+					buf[n] = 0;
+
+					dir_numbers[i] = atoi(buf);
+				}
+
+				isize closest_number_idx = -1;
+				for (isize i = 0; i < possible_valid_dirs.count; i++) {
+					if (dir_numbers[i] >= ODIN_ANDROID_API_LEVEL) {
+						if (closest_number_idx < 0) {
+							closest_number_idx = i;
+						} else if (dir_numbers[i] < dir_numbers[closest_number_idx]) {
+							closest_number_idx = i;
+						}
+					}
+				}
+
+				if (closest_number_idx < 0) {
+					gb_printf_err("Unable to find any Android SDK/API Level in %.*s meeting the minimum API level of %d\n", LIT(android_sdk_build_tools), ODIN_ANDROID_API_LEVEL);
+					return 1;
+				}
+
+				String api_number = possible_valid_dirs[closest_number_idx].name;
+
+				android_sdk_build_tools = concatenate_strings(temporary_allocator(), android_sdk_build_tools, api_number);
+				String android_sdk_platforms = concatenate_strings(temporary_allocator(),
+					build_context.ODIN_ANDROID_SDK,
+					make_string_c(gb_bprintf("platforms/android-%d/", dir_numbers[closest_number_idx]))
+				);
+
+
+
+				android_sdk_build_tools = normalize_path(temporary_allocator(), android_sdk_build_tools, NIX_SEPARATOR_STRING);
+				android_sdk_platforms   = normalize_path(temporary_allocator(), android_sdk_platforms,   NIX_SEPARATOR_STRING);
+
+				gbString cmd = gb_string_make(heap_allocator(), "");
+				defer (gb_string_free(cmd));
+
+				TIME_SECTION("Android aapt");
+
+				cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len);
+				cmd = gb_string_appendc(cmd, "aapt");
+				cmd = gb_string_appendc(cmd, " package -f");
+				cmd = gb_string_append_fmt(cmd, " -M \"%.*s\"", LIT(build_context.android_manifest));
+				cmd = gb_string_append_fmt(cmd, " -I \"%.*sandroid.jar\"", LIT(android_sdk_platforms));
+				cmd = gb_string_append_fmt(cmd, " -F \"%.*s.apk-build\"", LIT(output_filename));
+
+				result = system_exec_command_line_app("android-aapt", cmd);
+				if (result) {
+					return result;
+				}
+
+				TIME_SECTION("Android jarsigner");
+				gb_string_clear(cmd);
+
+				cmd = gb_string_append_length(cmd, build_context.ODIN_ANDROID_JAR_SIGNER.text, build_context.ODIN_ANDROID_JAR_SIGNER.len);
+				cmd = gb_string_append_fmt(cmd, " -storepass android -keystore \"%.*s\" \"%.*s.apk-build\" \"%.*s\"",
+					LIT(build_context.android_keystore),
+					LIT(output_filename),
+					LIT(build_context.android_keystore_alias)
+				);
+				result = system_exec_command_line_app("android-jarsigner", cmd);
+				if (result) {
+					return result;
+				}
+
+				TIME_SECTION("Android zipalign");
+				gb_string_clear(cmd);
+
+				cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len);
+				cmd = gb_string_appendc(cmd, "zipalign");
+				cmd = gb_string_appendc(cmd, " -f 4");
+				cmd = gb_string_append_fmt(cmd, " \"%.*s.apk-build\" \"%.*s.apk\"", LIT(output_filename), LIT(output_filename));
+
+
+				result = system_exec_command_line_app("android-zipalign", cmd);
+				if (result) {
+					return result;
+				}
+			}
 		}
 	}
 

+ 22 - 0
src/main.cpp

@@ -408,6 +408,10 @@ enum BuildFlagKind {
 	BuildFlag_Subsystem,
 #endif
 
+	BuildFlag_AndroidKeystore,
+	BuildFlag_AndroidKeystoreAlias,
+	BuildFlag_AndroidManifest,
+
 	BuildFlag_COUNT,
 };
 
@@ -624,6 +628,10 @@ gb_internal bool parse_build_flags(Array<String> args) {
 	add_flag(&build_flags, BuildFlag_Subsystem,               str_lit("subsystem"),                 BuildFlagParam_String,  Command__does_build);
 #endif
 
+	add_flag(&build_flags, BuildFlag_AndroidKeystore,         str_lit("android-keystore"),          BuildFlagParam_String,  Command__does_build);
+	add_flag(&build_flags, BuildFlag_AndroidKeystoreAlias,    str_lit("android-keystore-alias"),    BuildFlagParam_String,  Command__does_build);
+	add_flag(&build_flags, BuildFlag_AndroidManifest,         str_lit("android-manifest"),          BuildFlagParam_String,  Command__does_build);
+
 
 	GB_ASSERT(args.count >= 3);
 	Array<String> flag_args = array_slice(args, 3, args.count);
@@ -1638,6 +1646,20 @@ gb_internal bool parse_build_flags(Array<String> args) {
 						}
 					#endif
 
+						case BuildFlag_AndroidKeystore:
+							GB_ASSERT(value.kind == ExactValue_String);
+							build_context.android_keystore = value.value_string;
+							break;
+
+						case BuildFlag_AndroidKeystoreAlias:
+							GB_ASSERT(value.kind == ExactValue_String);
+							build_context.android_keystore_alias = value.value_string;
+							break;
+
+						case BuildFlag_AndroidManifest:
+							GB_ASSERT(value.kind == ExactValue_String);
+							build_context.android_manifest = value.value_string;
+							break;
 						}
 					}