[ios] Update sample to build the app as a framework To demonstrate fix for https://crbug.com/gn/337, update the sample application to build the application as a framework with a shell app that `dlopen()` the framework and call the entry point. Fixed: 337 Change-Id: I939f0736856a45725549f62cca72e09a1f0e0f0e Reviewed-on: https://gn-review.googlesource.com/c/gn/+/15461 Reviewed-by: Takuto Ikuta <tikuta@google.com> Commit-Queue: Sylvain Defresne <sdefresne@chromium.org>
diff --git a/examples/ios/app/BUILD.gn b/examples/ios/app/BUILD.gn index fdb3d03..af3d7cc 100644 --- a/examples/ios/app/BUILD.gn +++ b/examples/ios/app/BUILD.gn
@@ -3,13 +3,21 @@ # found in the LICENSE file. import("//build/config/ios/templates/ios_app_bundle.gni") +import("//build/config/ios/templates/ios_framework_bundle.gni") import("//build/config/ios/templates/storyboards.gni") ios_app_bundle("hello") { output_name = "Hello" - info_plist = "resources/Info.plist" + sources = [ "main.m" ] + + deps = [ ":hello_framework+bundle" ] +} + +ios_framework_bundle("hello_framework") { + output_name = "HelloMain" + sources = [ "AppDelegate.h", "AppDelegate.m", @@ -17,7 +25,7 @@ "SceneDelegate.m", "ViewController.h", "ViewController.m", - "main.m", + "hello_main.m", ] frameworks = [
diff --git a/examples/ios/app/hello_main.m b/examples/ios/app/hello_main.m new file mode 100644 index 0000000..feffc55 --- /dev/null +++ b/examples/ios/app/hello_main.m
@@ -0,0 +1,16 @@ +// Copyright 2023 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <UIKit/UIKit.h> + +#import "app/AppDelegate.h" + +int hello_main(int argc, char** argv) { + NSString* appDelegateClassName; + @autoreleasepool { + appDelegateClassName = NSStringFromClass([AppDelegate class]); + } + + return UIApplicationMain(argc, argv, nil, appDelegateClassName); +}
diff --git a/examples/ios/app/main.m b/examples/ios/app/main.m index b01cb7a..5c27b89 100644 --- a/examples/ios/app/main.m +++ b/examples/ios/app/main.m
@@ -1,15 +1,65 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import <UIKit/UIKit.h> -#import "app/AppDelegate.h" +#include <dlfcn.h> +#include <mach-o/dyld.h> +#include <stdlib.h> +#include <string.h> + +typedef int (*entry_point)(int, char**); + +static char kMainRelativePath[] = "/Frameworks/HelloMain.framework/HelloMain"; + +static char* GetHelloMainPath(void) { + uint32_t buffer_size = 0; + _NSGetExecutablePath(NULL, &buffer_size); + if (buffer_size == 0) + return NULL; + + uint32_t suffix_len = sizeof(kMainRelativePath) + 1; + if (buffer_size >= UINT32_MAX - suffix_len) + return NULL; + + char* buffer = malloc(suffix_len + buffer_size); + if (!buffer) + return NULL; + + if (_NSGetExecutablePath(buffer, &buffer_size) != 0) + return NULL; + + char* last_sep = strrchr(buffer, '/'); + if (!last_sep) + return NULL; + + memcpy(last_sep, kMainRelativePath, suffix_len); + return buffer; +} int main(int argc, char** argv) { - NSString* appDelegateClassName; - @autoreleasepool { - appDelegateClassName = NSStringFromClass([AppDelegate class]); + char* hello_main_path = GetHelloMainPath(); + if (!hello_main_path) + return 1; + + void* hello_main_handle = dlopen(hello_main_path, RTLD_NOW); + if (!hello_main_handle) + return 1; + + free(hello_main_path); + hello_main_path = NULL; + + entry_point hello_main_entry = dlsym(hello_main_handle, "hello_main"); + if (!hello_main_entry) + return 1; + + int retcode = hello_main_entry(argc, argv); + if (retcode) { + return retcode; } - return UIApplicationMain(argc, argv, nil, appDelegateClassName); + if (!dlclose(hello_main_handle)) { + return 1; + } + + return 0; }
diff --git a/examples/ios/build/config/ios/templates/ios_binary_bundle.gni b/examples/ios/build/config/ios/templates/ios_binary_bundle.gni index 43ec355..1e7b73d 100644 --- a/examples/ios/build/config/ios/templates/ios_binary_bundle.gni +++ b/examples/ios/build/config/ios/templates/ios_binary_bundle.gni
@@ -94,6 +94,7 @@ } bundle_data(_plist_bundle) { + product_type = invoker.product_type public_deps = [ ":$_plist_target" ] sources = [ "$target_out_dir/$_plist_target/Info.plist" ] outputs = [ "{{bundle_contents_dir}}/Info.plist" ]
diff --git a/examples/ios/build/config/ios/templates/ios_framework_bundle.gni b/examples/ios/build/config/ios/templates/ios_framework_bundle.gni index 13db266..805060e 100644 --- a/examples/ios/build/config/ios/templates/ios_framework_bundle.gni +++ b/examples/ios/build/config/ios/templates/ios_framework_bundle.gni
@@ -47,6 +47,7 @@ _bundle_identifier_prefix = invoker.bundle_identifier_prefix } + _product_type = "com.apple.product-type.framework" _bundle_identifier = "$_bundle_identifier_prefix.$_output_name" shared_library(_dylib_target) { @@ -79,6 +80,7 @@ } bundle_data(_dylib_bundle) { + product_type = _product_type public_deps = [ ":$_dylib_target" ] sources = [ "$target_out_dir/$_dylib_target/$_output_name" ] outputs = [ "{{bundle_executable_dir}}/{{source_file_part}}" ] @@ -99,6 +101,7 @@ _headers_bundle = target_name + "_headers_bundle" bundle_data(_headers_bundle) { + product_type = _product_type sources = invoker.public_headers + [ _umbrella_output ] outputs = [ "{{bundle_resources_dir}}/Headers/{{source_file_part}}" ] public_deps = [ ":$_umbrella_target" ] @@ -127,7 +130,8 @@ ]) output_name = _output_name - product_type = "com.apple.product-type.framework" + product_type = _product_type + transparent = true bundle_identifier = _bundle_identifier bundle_extension = "framework"