run method

Future<void> run({
  1. required BuildConfig buildConfig,
  2. required BuildOutput buildOutput,
  3. required Logger? logger,
})

Runs the Golang Compiler.

Completes with an error if the build fails.

Implementation

Future<void> run({
  required BuildConfig buildConfig,
  required BuildOutput buildOutput,
  required Logger? logger,
}) async {
  final outDir = buildConfig.outputDirectory;
  final packageRoot = buildConfig.packageRoot;
  await Directory.fromUri(outDir).create(recursive: true);
  var linkMode = _linkMode(buildConfig.linkModePreference);
  final libUri = outDir.resolve(
    buildConfig.targetOS.libraryFileName(name, linkMode),
  );
  final bridgePath = packageRoot.resolveUri(Uri.file(this.bridgePath));
  final resolver = CompilerResolver(buildConfig: buildConfig, logger: logger);

  if (!buildConfig.dryRun) {
    final compiler = await resolver.resolveCompiler();
    var buildMode = linkMode == StaticLinking() ? "c-archive" : "c-shared";
    var goLib = libUri;

    final env = {
      "CGO_ENABLED": "1",
    };

    String buildArch;
    switch (buildConfig.targetArchitecture) {
      case Architecture.arm:
        buildArch = "arm";
      case Architecture.arm64:
        buildArch = "arm64";
      case Architecture.ia32:
        buildArch = "386";
      case Architecture.x64:
        buildArch = "amd64";
      default:
        throw Exception("Unknown architecture");
    }

    String buildOs;
    switch (buildConfig.targetOS) {
      case OS.windows:
        buildOs = "windows";

      case OS.linux:
        buildOs = "linux";

      case OS.android:
        buildOs = "android";

        // The Android Gradle plugin does not honor API level 19 and 20 when
        // invoking clang. Mimic that behavior here.
        // See https://github.com/dart-lang/native/issues/171.
        final minimumApi =
            buildConfig.targetArchitecture == Architecture.riscv64 ? 35 : 21;
        final targetAndroidNdkApi =
            max(buildConfig.targetAndroidNdkApi!, minimumApi);

        final cc = compiler.uri.resolve(
            './${androidNdkClangTargetFlags[buildConfig.targetArchitecture]!}$targetAndroidNdkApi-clang');
        env["CC"] = cc.toFilePath();

      case OS.iOS:
        buildOs = "ios";
        buildMode = "c-archive";
        goLib = outDir.resolve('out.o');

      case OS.macOS:
        buildOs = "darwin";

      default:
        throw Exception("Unknown os");
    }

    env["GOOS"] = buildOs;
    env["GOARCH"] = buildArch;

    await runProcess(
      executable: Uri.file("go"),
      environment: env,
      arguments: [
        "build",
        "-buildmode=$buildMode",
        if (buildConfig.buildMode != BuildMode.debug) '-ldflags=-s -w',
        '-o',
        goLib.toFilePath(),
        bridgePath.toFilePath(),
      ],
      logger: logger,
      captureOutput: false,
      throwOnUnexpectedExitCode: true,
    );

    if (buildConfig.targetOS == OS.iOS) {
      //xcrun -sdk iphoneos clang -arch armv7 -fpic -shared -Wl,-all_load
      // libmystatic.a -framework Corefoundation -o libmydynamic.dylib
      await runProcess(
        executable: compiler.uri,
        arguments: [
          '-fpic',
          '-shared',
          '-Wl,-all_load,-force_load',
          goLib.toFilePath(),
          '-framework',
          'CoreFoundation',
          '-o',
          libUri.toFilePath(),
        ],
        logger: logger,
        captureOutput: false,
        throwOnUnexpectedExitCode: true,
      );
    }
  }

  if (assetName != null) {
    buildOutput.addAssets([
      NativeCodeAsset(
        package: buildConfig.packageName,
        name: assetName!,
        file: libUri,
        linkMode: linkMode,
        os: buildConfig.targetOS,
        architecture:
            buildConfig.dryRun ? null : buildConfig.targetArchitecture,
      )
    ]);
  }

  if (!buildConfig.dryRun) {
    final sources = [
      bridgePath,
      for (final source in this.sources)
        packageRoot.resolveUri(Uri.file(source)),
    ];
    final dartBuildFiles = [
      for (final source in this.dartBuildFiles) packageRoot.resolve(source),
    ];

    final sourceFiles = await Stream.fromIterable(sources)
        .asyncExpand(
          (path) => Directory(path.toFilePath())
              .list(recursive: true)
              .where((entry) => entry is File)
              .map((file) => file.uri),
        )
        .toList();

    buildOutput.addDependencies({
      ...sourceFiles,
      ...dartBuildFiles,
    });
  }
}