From 3bfe024e2f63ac34239648d3c77287bd35c162b2 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 23 Jul 2024 16:01:56 +0200 Subject: [PATCH] Changes as per review --- .../lib/native_toolchain_c.dart | 3 +- .../lib/src/cbuilder/cbuilder.dart | 224 ++++-------------- .../lib/src/cbuilder/clinker.dart | 142 ++--------- .../lib/src/cbuilder/ctool.dart | 132 +++++++++++ .../lib/src/cbuilder/language.dart | 27 +++ .../lib/src/cbuilder/linker_options.dart | 28 ++- .../lib/src/cbuilder/linkmode.dart | 11 + .../lib/src/cbuilder/output_type.dart | 8 + .../lib/src/cbuilder/run_cbuilder.dart | 6 +- .../test/clinker/build_testfiles.dart | 49 ++++ .../test/clinker/objects_test.dart | 25 +- .../test/clinker/testfiles/linker/test.a | Bin 2950 -> 0 bytes .../test/clinker/testfiles/linker/test1.o | Bin 1360 -> 0 bytes .../test/clinker/testfiles/linker/test2.o | Bin 1368 -> 0 bytes .../test/clinker/treeshake_test.dart | 62 +++-- pkgs/native_toolchain_c/test/helpers.dart | 11 + 16 files changed, 362 insertions(+), 366 deletions(-) create mode 100644 pkgs/native_toolchain_c/lib/src/cbuilder/ctool.dart create mode 100644 pkgs/native_toolchain_c/lib/src/cbuilder/language.dart create mode 100644 pkgs/native_toolchain_c/lib/src/cbuilder/linkmode.dart create mode 100644 pkgs/native_toolchain_c/lib/src/cbuilder/output_type.dart create mode 100644 pkgs/native_toolchain_c/test/clinker/build_testfiles.dart delete mode 100644 pkgs/native_toolchain_c/test/clinker/testfiles/linker/test.a delete mode 100644 pkgs/native_toolchain_c/test/clinker/testfiles/linker/test1.o delete mode 100644 pkgs/native_toolchain_c/test/clinker/testfiles/linker/test2.o diff --git a/pkgs/native_toolchain_c/lib/native_toolchain_c.dart b/pkgs/native_toolchain_c/lib/native_toolchain_c.dart index 0bca50ed0..2f96f89ab 100644 --- a/pkgs/native_toolchain_c/lib/native_toolchain_c.dart +++ b/pkgs/native_toolchain_c/lib/native_toolchain_c.dart @@ -5,6 +5,7 @@ /// A library to invoke the native C compiler installed on the host machine. library; -export 'src/cbuilder/cbuilder.dart' show CBuilder, Language; +export 'src/cbuilder/cbuilder.dart' show CBuilder; export 'src/cbuilder/clinker.dart' show CLinker, LinkerOptions; +export 'src/cbuilder/language.dart' show Language; export 'src/utils/env_from_bat.dart'; diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart index 053c7414a..d2202b737 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart @@ -8,82 +8,14 @@ import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; import 'package:native_assets_cli/native_assets_cli.dart'; +import 'ctool.dart'; +import 'language.dart'; +import 'linkmode.dart'; +import 'output_type.dart'; import 'run_cbuilder.dart'; -/// A programming language that can be selected for compilation of source files. -/// -/// See [CBuilder.language] for more information. -class Language { - /// The name of the language. - final String name; - - const Language._(this.name); - - static const Language c = Language._('c'); - - static const Language cpp = Language._('c++'); - - static const Language objectiveC = Language._('objective c'); - - /// Known values for [Language]. - static const List values = [ - c, - cpp, - objectiveC, - ]; - - @override - String toString() => name; -} - /// Specification for building an artifact with a C compiler. -class CBuilder implements Builder { - /// What kind of artifact to build. - final CBuilderType _type; - - /// Name of the library or executable to build. - /// - /// The filename will be decided by [BuildConfig.targetOS] and - /// [OS.libraryFileName] or [OS.executableFileName]. - /// - /// File will be placed in [BuildConfig.outputDirectory]. - final String name; - - /// Asset identifier. - /// - /// Used to output the [BuildOutput.assets]. - /// - /// If omitted, no asset will be added to the build output. - final String? assetName; - - /// Sources to build the library or executable. - /// - /// Resolved against [BuildConfig.packageRoot]. - /// - /// Used to output the [BuildOutput.dependencies]. - final List sources; - - /// Include directories to pass to the compiler. - /// - /// Resolved against [BuildConfig.packageRoot]. - /// - /// Used to output the [BuildOutput.dependencies]. - final List includes; - - /// Frameworks to link. - /// - /// Only effective if [language] is [Language.objectiveC]. - /// - /// Defaults to `['Foundation']`. - /// - /// Not used to output the [BuildOutput.dependencies], frameworks can be - /// mentioned by name if they are available on the system, so the file path - /// is not known. If you're depending on your own frameworks add them to - /// [BuildOutput.dependencies] manually. - final List frameworks; - - static const List _defaultFrameworks = ['Foundation']; - +class CBuilder extends CTool implements Builder { /// The dart files involved in building this artifact. /// /// Resolved against [BuildConfig.packageRoot]. @@ -95,19 +27,6 @@ class CBuilder implements Builder { ) final List dartBuildFiles; - /// TODO(https://github.com/dart-lang/native/issues/54): Move to [BuildConfig] - /// or hide in public API. - @visibleForTesting - final Uri? installName; - - /// Flags to pass to the compiler. - final List flags; - - /// Definitions of preprocessor macros. - /// - /// When the value is `null`, the macro is defined without a value. - final Map defines; - /// Whether to define a macro for the current [BuildMode]. /// /// The macro name is the uppercase name of the build mode and does not have a @@ -127,100 +46,54 @@ class CBuilder implements Builder { /// Defaults to `true`. final bool ndebugDefine; - /// Whether the compiler will emit position independent code. - /// - /// When set to `true`, libraries will be compiled with `-fPIC` and - /// executables with `-fPIE`. Accordingly the corresponding parameter of the - /// [CBuilder.executable] constructor is named `pie`. - /// - /// When set to `null`, the default behavior of the compiler will be used. - /// - /// This option has no effect when building for Windows, where generation of - /// position independent code is not configurable. - /// - /// Defaults to `true` for libraries and `false` for executables. - final bool? pic; - - /// The language standard to use. - /// - /// When set to `null`, the default behavior of the compiler will be used. - final String? std; - - /// The language to compile [sources] as. - /// - /// [cppLinkStdLib] only has an effect when this option is set to - /// [Language.cpp]. - final Language language; - - /// The C++ standard library to link against. - /// - /// This option has no effect when [language] is not set to [Language.cpp] or - /// when compiling for Windows. - /// - /// When set to `null`, the following defaults will be used, based on the - /// target OS: - /// - /// | OS | Library | - /// | :------ | :----------- | - /// | Android | `c++_shared` | - /// | iOS | `c++` | - /// | Linux | `stdc++` | - /// | macOS | `c++` | - /// | Fuchsia | `c++` | - final String? cppLinkStdLib; - - /// If the code asset should be a dynamic or static library. - /// - /// This determines whether to produce a dynamic or static library. If null, - /// the value is instead retrieved from the [BuildConfig]. - final LinkModePreference? linkModePreference; - CBuilder.library({ - required this.name, - required this.assetName, - this.sources = const [], - this.includes = const [], - this.frameworks = _defaultFrameworks, + required super.name, + super.assetName, + super.sources = const [], + super.includes = const [], + super.frameworks = CTool.defaultFrameworks, @Deprecated( 'Newer Dart and Flutter SDKs automatically add the Dart hook ' 'sources as dependencies.', ) this.dartBuildFiles = const [], - @visibleForTesting this.installName, - this.flags = const [], - this.defines = const {}, + @visibleForTesting super.installName, + super.flags = const [], + super.defines = const {}, this.buildModeDefine = true, this.ndebugDefine = true, - this.pic = true, - this.std, - this.language = Language.c, - this.cppLinkStdLib, - this.linkModePreference, - }) : _type = CBuilderType.library; + super.pic = true, + super.std, + super.language = Language.c, + super.cppLinkStdLib, + super.linkModePreference, + }) : super(type: OutputType.library); CBuilder.executable({ - required this.name, - this.sources = const [], - this.includes = const [], - this.frameworks = _defaultFrameworks, + required super.name, + super.sources = const [], + super.includes = const [], + super.frameworks = CTool.defaultFrameworks, @Deprecated( 'Newer Dart and Flutter SDKs automatically add the Dart hook ' 'sources as dependencies.', ) this.dartBuildFiles = const [], - this.flags = const [], - this.defines = const {}, + super.flags = const [], + super.defines = const {}, this.buildModeDefine = true, this.ndebugDefine = true, bool? pie = false, - this.std, - this.language = Language.c, - this.cppLinkStdLib, - }) : _type = CBuilderType.executable, - assetName = null, - installName = null, - pic = pie, - linkModePreference = null; + super.std, + super.language = Language.c, + super.cppLinkStdLib, + }) : super( + type: OutputType.executable, + assetName: null, + installName: null, + pic: pie, + linkModePreference: null, + ); /// Runs the C Compiler with on this C build spec. /// @@ -264,14 +137,14 @@ class CBuilder implements Builder { includes: includes, frameworks: frameworks, dynamicLibrary: - _type == CBuilderType.library && linkMode == DynamicLoadingBundled() + type == OutputType.library && linkMode == DynamicLoadingBundled() ? libUri : null, - staticLibrary: - _type == CBuilderType.library && linkMode == StaticLinking() - ? libUri - : null, - executable: _type == CBuilderType.executable ? exeUri : null, + staticLibrary: type == OutputType.library && linkMode == StaticLinking() + ? libUri + : null, + executable: type == OutputType.executable ? exeUri : null, + // ignore: invalid_use_of_visible_for_testing_member installName: installName, flags: flags, defines: { @@ -322,18 +195,3 @@ class CBuilder implements Builder { } } } - -enum CBuilderType { - executable, - library, -} - -LinkMode getLinkMode(LinkModePreference preference) { - if (preference == LinkModePreference.dynamic || - preference == LinkModePreference.preferDynamic) { - return DynamicLoadingBundled(); - } - assert(preference == LinkModePreference.static || - preference == LinkModePreference.preferStatic); - return StaticLinking(); -} diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart index 1560827c8..1ac1d34b1 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart @@ -1,4 +1,4 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. @@ -8,136 +8,35 @@ import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; import 'package:native_assets_cli/native_assets_cli.dart'; -import 'cbuilder.dart'; +import 'ctool.dart'; +import 'language.dart'; import 'linker_options.dart'; +import 'linkmode.dart'; +import 'output_type.dart'; import 'run_cbuilder.dart'; export 'linker_options.dart'; /// Specification for linking an artifact with a C linker. -class CLinker implements Linker { - /// Name of the library or executable to linkg. - /// - /// The filename will be decided by [LinkConfig.targetOS] and - /// [OS.libraryFileName] or [OS.executableFileName]. - /// - /// File will be placed in [LinkConfig.outputDirectory]. - final String name; - - /// Asset identifier. - /// - /// Used to output the [LinkConfig.assets]. - /// - /// If omitted, no asset will be added to the build output. - final String? assetName; - - /// Sources to build the library or executable. - /// - /// Resolved against [LinkConfig.packageRoot]. - /// - /// Used to output the [LinkOutput.dependencies]. - final List sources; - - /// Include directories to pass to the linker. - /// - /// Resolved against [LinkConfig.packageRoot]. - /// - /// Used to output the [LinkOutput.dependencies]. - final List includes; - - /// Frameworks to link. - /// - /// Only effective if [language] is [Language.objectiveC]. - /// - /// Defaults to `['Foundation']`. - /// - /// Not used to output the [LinkOutput.dependencies], frameworks can be - /// mentioned by name if they are available on the system, so the file path - /// is not known. If you're depending on your own frameworks add them to - /// [LinkOutput.dependencies] manually. - final List frameworks; - - static const List _defaultFrameworks = ['Foundation']; - - /// TODO(https://github.com/dart-lang/native/issues/54): Move to [LinkConfig] - /// or hide in public API. - @visibleForTesting - final Uri? installName; - - /// Flags to pass to the linker. - final List flags; - - /// Definitions of preprocessor macros. - /// - /// When the value is `null`, the macro is defined without a value. - final Map defines; - - /// Whether the linker will emit position independent code. - /// - /// When set to `true`, libraries will be compiled with `-fPIC` and - /// executables with `-fPIE`. Accordingly the corresponding parameter of the - /// [CBuilder.executable] constructor is named `pie`. - /// - /// When set to `null`, the default behavior of the linker will be used. - /// - /// This option has no effect when building for Windows, where generation of - /// position independent code is not configurable. - /// - /// Defaults to `true` for libraries and `false` for executables. - final bool? pic; - - /// The language standard to use. - /// - /// When set to `null`, the default behavior of the linker will be used. - final String? std; - - /// The language to compile [sources] as. - /// - /// [cppLinkStdLib] only has an effect when this option is set to - /// [Language.cpp]. - final Language language; - - /// The C++ standard library to link against. - /// - /// This option has no effect when [language] is not set to [Language.cpp] or - /// when compiling for Windows. - /// - /// When set to `null`, the following defaults will be used, based on the - /// target OS: - /// - /// | OS | Library | - /// | :------ | :----------- | - /// | Android | `c++_shared` | - /// | iOS | `c++` | - /// | Linux | `stdc++` | - /// | macOS | `c++` | - /// | Fuchsia | `c++` | - final String? cppLinkStdLib; - - /// If the code asset should be a dynamic or static library. - /// - /// This determines whether to produce a dynamic or static library. If null, - /// the value is instead retrieved from the [LinkConfig]. - final LinkModePreference? linkModePreference; - +class CLinker extends CTool implements Linker { final LinkerOptions linkerOptions; CLinker.library({ - required this.name, - required this.assetName, + required super.name, + super.assetName, required this.linkerOptions, - this.sources = const [], - this.includes = const [], - this.frameworks = _defaultFrameworks, - @visibleForTesting this.installName, - this.flags = const [], - this.defines = const {}, - this.pic = true, - this.std, - this.language = Language.c, - this.cppLinkStdLib, - this.linkModePreference, - }); + super.sources = const [], + super.includes = const [], + super.frameworks = CTool.defaultFrameworks, + @visibleForTesting super.installName, + super.flags = const [], + super.defines = const {}, + super.pic = true, + super.std, + super.language = Language.c, + super.cppLinkStdLib, + super.linkModePreference, + }) : super(type: OutputType.library); /// Runs the C Linker with on this C build spec. /// @@ -173,6 +72,7 @@ class CLinker implements Linker { frameworks: frameworks, dynamicLibrary: linkMode == DynamicLoadingBundled() ? libUri : null, staticLibrary: linkMode == StaticLinking() ? libUri : null, + // ignore: invalid_use_of_visible_for_testing_member installName: installName, flags: flags, defines: defines, diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/ctool.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/ctool.dart new file mode 100644 index 000000000..04cf369cc --- /dev/null +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/ctool.dart @@ -0,0 +1,132 @@ +import 'package:meta/meta.dart'; +import 'package:native_assets_cli/native_assets_cli.dart'; + +import 'cbuilder.dart'; +import 'language.dart'; +import 'output_type.dart'; + +abstract class CTool { + /// What kind of artifact to build. + final OutputType type; + + /// Name of the library or executable to linkg. + /// + /// The filename will be decided by [LinkConfig.targetOS] and + /// [OS.libraryFileName] or [OS.executableFileName]. + /// + /// File will be placed in [LinkConfig.outputDirectory]. + final String name; + + /// Asset identifier. + /// + /// Used to output the [LinkConfig.assets]. + /// + /// If omitted, no asset will be added to the build output. + final String? assetName; + + /// Sources to build the library or executable. + /// + /// Resolved against [LinkConfig.packageRoot]. + /// + /// Used to output the [LinkOutput.dependencies]. + final List sources; + + /// Include directories to pass to the linker. + /// + /// Resolved against [LinkConfig.packageRoot]. + /// + /// Used to output the [LinkOutput.dependencies]. + final List includes; + + /// Frameworks to link. + /// + /// Only effective if [language] is [Language.objectiveC]. + /// + /// Defaults to `['Foundation']`. + /// + /// Not used to output the [LinkOutput.dependencies], frameworks can be + /// mentioned by name if they are available on the system, so the file path + /// is not known. If you're depending on your own frameworks add them to + /// [LinkOutput.dependencies] manually. + final List frameworks; + + static const List defaultFrameworks = ['Foundation']; + + /// TODO(https://github.com/dart-lang/native/issues/54): Move to [LinkConfig] + /// or hide in public API. + @visibleForTesting + final Uri? installName; + + /// Flags to pass to the linker. + final List flags; + + /// Definitions of preprocessor macros. + /// + /// When the value is `null`, the macro is defined without a value. + final Map defines; + + /// Whether the linker will emit position independent code. + /// + /// When set to `true`, libraries will be compiled with `-fPIC` and + /// executables with `-fPIE`. Accordingly the corresponding parameter of the + /// [CBuilder.executable] constructor is named `pie`. + /// + /// When set to `null`, the default behavior of the linker will be used. + /// + /// This option has no effect when building for Windows, where generation of + /// position independent code is not configurable. + /// + /// Defaults to `true` for libraries and `false` for executables. + final bool? pic; + + /// The language standard to use. + /// + /// When set to `null`, the default behavior of the linker will be used. + final String? std; + + /// The language to compile [sources] as. + /// + /// [cppLinkStdLib] only has an effect when this option is set to + /// [Language.cpp]. + final Language language; + + /// The C++ standard library to link against. + /// + /// This option has no effect when [language] is not set to [Language.cpp] or + /// when compiling for Windows. + /// + /// When set to `null`, the following defaults will be used, based on the + /// target OS: + /// + /// | OS | Library | + /// | :------ | :----------- | + /// | Android | `c++_shared` | + /// | iOS | `c++` | + /// | Linux | `stdc++` | + /// | macOS | `c++` | + /// | Fuchsia | `c++` | + final String? cppLinkStdLib; + + /// If the code asset should be a dynamic or static library. + /// + /// This determines whether to produce a dynamic or static library. If null, + /// the value is instead retrieved from the [LinkConfig]. + final LinkModePreference? linkModePreference; + + CTool({ + required this.name, + required this.assetName, + required this.sources, + required this.includes, + required this.frameworks, + required this.installName, + required this.flags, + required this.defines, + required this.pic, + required this.std, + required this.language, + required this.cppLinkStdLib, + required this.linkModePreference, + required this.type, + }); +} diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/language.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/language.dart new file mode 100644 index 000000000..a46dc20ac --- /dev/null +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/language.dart @@ -0,0 +1,27 @@ +import 'cbuilder.dart'; + +/// A programming language that can be selected for compilation of source files. +/// +/// See [CBuilder.language] for more information. +class Language { + /// The name of the language. + final String name; + + const Language._(this.name); + + static const Language c = Language._('c'); + + static const Language cpp = Language._('c++'); + + static const Language objectiveC = Language._('objective c'); + + /// Known values for [Language]. + static const List values = [ + c, + cpp, + objectiveC, + ]; + + @override + String toString() => name; +} diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/linker_options.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/linker_options.dart index 44529dd2a..136355135 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/linker_options.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/linker_options.dart @@ -7,6 +7,7 @@ import 'dart:io'; import '../native_toolchain/clang.dart'; import '../native_toolchain/gcc.dart'; import '../tool/tool.dart'; +import 'package:path/path.dart' as path; /// Options to pass to the linker. /// @@ -43,8 +44,9 @@ class LinkerOptions { gcSections = gcSections ?? true, _wholeArchiveSandwich = false; - /// Create linking options to tree-shake symbols from the input files. The - /// [symbols] specify the symbols which should be kept. + /// Create linking options to tree-shake symbols from the input files. + /// + /// The [symbols] specify the symbols which should be kept. LinkerOptions.treeshake({ Iterable? flags, required Iterable? symbols, @@ -64,8 +66,16 @@ class LinkerOptions { /// trick, which includes all symbols when linking object files. /// /// Throws if the [linker] is not supported. - Iterable preSourcesFlags(Tool linker) => - _toLinkerSyntax(linker, _wholeArchiveSandwich ? ['--whole-archive'] : []); + Iterable preSourcesFlags( + Tool linker, + Iterable sourceFiles, + ) => + _toLinkerSyntax( + linker, + sourceFiles.any((source) => path.extension(source) == '.a') || + _wholeArchiveSandwich + ? ['--whole-archive'] + : []); /// The flags for the specified [linker], which are inserted _after_ the /// sources. @@ -74,12 +84,18 @@ class LinkerOptions { /// trick, which includes all symbols when linking object files. /// /// Throws if the [linker] is not supported. - Iterable postSourcesFlags(Tool linker) => _toLinkerSyntax(linker, [ + Iterable postSourcesFlags( + Tool linker, + Iterable sourceFiles, + ) => + _toLinkerSyntax(linker, [ ..._linkerFlags, if (gcSections) '--gc-sections', if (linkerScript != null) '--version-script=${linkerScript!.toFilePath()}', - if (_wholeArchiveSandwich) '--no-whole-archive', + if (sourceFiles.any((source) => path.extension(source) == '.a') || + _wholeArchiveSandwich) + '--no-whole-archive', ]); Iterable _toLinkerSyntax(Tool linker, List flagList) { diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/linkmode.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/linkmode.dart new file mode 100644 index 000000000..c9f7190e6 --- /dev/null +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/linkmode.dart @@ -0,0 +1,11 @@ +import 'package:native_assets_cli/native_assets_cli.dart'; + +LinkMode getLinkMode(LinkModePreference preference) { + if (preference == LinkModePreference.dynamic || + preference == LinkModePreference.preferDynamic) { + return DynamicLoadingBundled(); + } + assert(preference == LinkModePreference.static || + preference == LinkModePreference.preferStatic); + return StaticLinking(); +} diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/output_type.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/output_type.dart new file mode 100644 index 000000000..d413afe94 --- /dev/null +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/output_type.dart @@ -0,0 +1,8 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +enum OutputType { + executable, + library, +} diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart index 39c014058..dd0d0ea3a 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart @@ -15,8 +15,8 @@ import '../native_toolchain/xcode.dart'; import '../tool/tool_instance.dart'; import '../utils/env_from_bat.dart'; import '../utils/run_process.dart'; -import 'cbuilder.dart'; import 'compiler_resolver.dart'; +import 'language.dart'; import 'linker_options.dart'; class RunCBuilder { @@ -267,7 +267,7 @@ class RunCBuilder { '-l', cppLinkStdLib ?? defaultCppLinkStdLib[config.targetOS]! ], - ...linkerOptions?.preSourcesFlags(compiler.tool) ?? [], + ...linkerOptions?.preSourcesFlags(compiler.tool, sourceFiles) ?? [], ...flags, for (final MapEntry(key: name, :value) in defines.entries) if (value == null) '-D$name' else '-D$name=$value', @@ -292,7 +292,7 @@ class RunCBuilder { '-o', outFile!.toFilePath(), ], - ...linkerOptions?.postSourcesFlags(compiler.tool) ?? [], + ...linkerOptions?.postSourcesFlags(compiler.tool, sourceFiles) ?? [], ], logger: logger, captureOutput: false, diff --git a/pkgs/native_toolchain_c/test/clinker/build_testfiles.dart b/pkgs/native_toolchain_c/test/clinker/build_testfiles.dart new file mode 100644 index 000000000..39ee0f1b0 --- /dev/null +++ b/pkgs/native_toolchain_c/test/clinker/build_testfiles.dart @@ -0,0 +1,49 @@ +import 'dart:io'; + +import 'package:native_assets_cli/native_assets_cli.dart'; +import 'package:native_toolchain_c/native_toolchain_c.dart'; + +import '../helpers.dart'; + +Future buildTestArchive(Uri tempUri) async { + final test1Uri = packageUri.resolve('test/clinker/testfiles/linker/test1.c'); + final test2Uri = packageUri.resolve('test/clinker/testfiles/linker/test2.c'); + if (!await File.fromUri(test1Uri).exists() || + !await File.fromUri(test2Uri).exists()) { + throw Exception('Run the test from the root directory.'); + } + const name = 'static_test'; + + final logMessages = []; + final logger = createCapturingLogger(logMessages); + + final buildConfig = BuildConfig.build( + outputDirectory: tempUri, + packageName: name, + packageRoot: tempUri, + targetArchitecture: Architecture.current, + targetOS: OS.current, + buildMode: BuildMode.release, + linkModePreference: LinkModePreference.dynamic, + cCompiler: CCompilerConfig( + compiler: cc, + envScript: envScript, + envScriptArgs: envScriptArgs, + ), + linkingEnabled: false, + ); + final buildOutput = BuildOutput(); + final cbuilder = CBuilder.library( + name: name, + assetName: 'somename', + sources: [test1Uri.toFilePath(), test2Uri.toFilePath()], + linkModePreference: LinkModePreference.static, + ); + await cbuilder.run( + config: buildConfig, + output: buildOutput, + logger: logger, + ); + + return buildOutput.assets.first.file!; +} diff --git a/pkgs/native_toolchain_c/test/clinker/objects_test.dart b/pkgs/native_toolchain_c/test/clinker/objects_test.dart index 1f0700d35..4eeb79ad6 100644 --- a/pkgs/native_toolchain_c/test/clinker/objects_test.dart +++ b/pkgs/native_toolchain_c/test/clinker/objects_test.dart @@ -10,10 +10,10 @@ import 'dart:io'; import 'package:native_assets_cli/native_assets_cli.dart'; import 'package:native_toolchain_c/native_toolchain_c.dart'; -import 'package:native_toolchain_c/src/utils/run_process.dart'; import 'package:test/test.dart'; import '../helpers.dart'; +import 'build_testfiles.dart'; Future main() async { if (!Platform.isLinux) { @@ -32,6 +32,8 @@ Future main() async { final linkOutput = LinkOutput(); final tempUri = await tempDirForTest(); + final uri = await buildTestArchive(tempUri); + final linkConfig = LinkConfig.build( outputDirectory: tempUri, packageName: 'testpackage', @@ -44,14 +46,9 @@ Future main() async { assets: []); await CLinker.library( name: name, - assetName: 'testassetname', + assetName: '', linkerOptions: LinkerOptions.manual(gcSections: false), - sources: [ - 'test/clinker/testfiles/linker/test1.o', - 'test/clinker/testfiles/linker/test2.o', - ] - .map((objectFile) => packageUri.resolve(objectFile).toFilePath()) - .toList(), + sources: [uri.toFilePath()], ).run( config: linkConfig, output: linkOutput, @@ -64,16 +61,8 @@ Future main() async { final file = (asset as NativeCodeAsset).file; expect(file, isNotNull, reason: 'Asset $asset has a file'); final filePath = file!.toFilePath(); - expect( - filePath, - endsWith(os.dylibFileName(name)), - ); - final readelf = (await runProcess( - executable: Uri.file('readelf'), - arguments: ['-WCs', filePath], - logger: logger, - )) - .stdout; + expect(filePath, endsWith(os.dylibFileName(name))); + final readelf = await executeReadelf(filePath); expect(readelf, contains('my_other_func')); expect(readelf, contains('my_func')); }); diff --git a/pkgs/native_toolchain_c/test/clinker/testfiles/linker/test.a b/pkgs/native_toolchain_c/test/clinker/testfiles/linker/test.a deleted file mode 100644 index b2733a3e7d710c5570d77d76fd492a3a8abe7ee1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2950 zcmeHIOKTKC5U$zHL)S!B5e!6RyojP1_eF>zVRhB)K|BPa2hnWrI?IG)XJw{^#DnG} z%8Yv1+<1&Ne$FiXs6EroXQ0s;=&??r$#KR8c2bEL?MkrIb=l zKi#@+wI&X&0s!Rj>jI2_>us%eUxXb%?CZdfjHdlqm%aXelC0V1Yi8PVb)H>Xh1YlQ z-^)1;CNSc_BK*|E3Q(jqu+$T*!!%66N^|FP^X)iUnmeC%3BOP?c=EAU0a$7@Zn&53 z`0X_ny5*`@@k(>$(q-I|Il=vi_lviJ31KhU^12i0K0nyb#boTCieca6sBOzPsm z*kZ>L>+~$hBzIwk?HAcjXPuVEX(iRS^Iyd=n)7$#%NR>@4%H5I$#2hV=fBSJvQJbK zdCKTA3P`-*Z5)uk_z=EIE2+Ni`v}L#X0LynV-^?%RDO+%7Yx@Q zo{MKv#i=LDI0P48!JByi8w)2L6)rxDd(Y(Jif8{OnUUc?C!4Da=I-$Sm2Cv}ozCLq zfE|Uajw&bHe}8-bS)APBGjkaQBwjF!leZeyG_#bZe;aLCx diff --git a/pkgs/native_toolchain_c/test/clinker/testfiles/linker/test1.o b/pkgs/native_toolchain_c/test/clinker/testfiles/linker/test1.o deleted file mode 100644 index c2eefc945c3ff72887db425d64ed99b13ea2981c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1360 zcmb_bJx|+E6unMTLMfnt7?9}T2^Fb4CA34^0i^_*3{?jt+5xrH366rO9b`YGgrV(( zlmRI}gP*|OfnQRoYxhcUkNqwiwDTGM%P!sUs%Q;e>~qHYBn0L+$Y<9`^XF3+B3DGs_V7tnsJ%8 z1Tvd*woA^S;;hV;r^kGN$DG3hTfy>rzH(k@%uT�^+|I&R(M5H+kh^?wb)6DLMay ztpuIMuj#BK27x`a2rTu{>b?9l2R6CAIMg27B^n<_;xfb@dubS`n)?@8; zj+p?N-#h3=Uf?H9|HI<)9=L-kYp=SAWsXv|zcth`le!QLem2CaiDwv*l5b(z~m|I+B?JvmJ5lR?*@fanFcxFEi8fM2sg z#<#g2xQ3j4{_jTf!k~c6U*cVM^6n4+G)(RZ_Xn-$C7;(Dx+^Sf;}qx-Bl_5S{I~Xu bA!%9tk%O6Z8t{t$J5PUUh~6DDb!`1D8M9jN diff --git a/pkgs/native_toolchain_c/test/clinker/testfiles/linker/test2.o b/pkgs/native_toolchain_c/test/clinker/testfiles/linker/test2.o deleted file mode 100644 index 3e88b1ae022ed48636909de42b6580ad30924d1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1368 zcmb_bO-md>5UttuD@Mac0udCMlPGGlyLw1GgpKRR9)btKco11bl^J*DE^00?|pFpn6;eG{4#(%#QpcA zyuoNJrH^|+?jw#ukCFqUBU4sQ@Q>>q)7D|V^*d<7VR#Uj7D@(LM#q@P@$i_Ke19Ku z)P?Xa`edX}9X)`Gj(y`b5KWk1Tf9*J@|4j>2GkGFc%T|l1S;$#L9^rgI>5D{W3<}X z++K)`*ZheBO4IFnEA)IF7yS>Di+j*r3|M6zIe&?_(8;>LKU_%eiSCbbC13cg+O+o-O=#T&;4LE6 ivGeKwweOBnYFvMcf|N1+%)Cc0EB`MGy=P_O*!fR1Ze9NX diff --git a/pkgs/native_toolchain_c/test/clinker/treeshake_test.dart b/pkgs/native_toolchain_c/test/clinker/treeshake_test.dart index 6108eab62..fe218e89c 100644 --- a/pkgs/native_toolchain_c/test/clinker/treeshake_test.dart +++ b/pkgs/native_toolchain_c/test/clinker/treeshake_test.dart @@ -10,42 +10,39 @@ import 'dart:io'; import 'package:native_assets_cli/native_assets_cli.dart'; import 'package:native_toolchain_c/native_toolchain_c.dart'; -import 'package:native_toolchain_c/src/utils/run_process.dart'; import 'package:test/test.dart'; import '../helpers.dart'; +import 'build_testfiles.dart'; -void main() { +Future main() async { if (!Platform.isLinux) { // Avoid needing status files on Dart SDK CI. return; } - final sources = [ - packageUri.resolve('test/clinker/testfiles/linker/test.a').toFilePath() - ]; - final linkerManual = CLinker.library( - name: 'mylibname', - assetName: 'assetName', - sources: sources, - linkerOptions: LinkerOptions.manual( - flags: ['--strip-debug', '-u', 'my_other_func'], - gcSections: true, - linkerScript: Uri.file('test/clinker/testfiles/linker/symbols.lds'), - ), - ); - final linkerAuto = CLinker.library( - name: 'mylibname', - assetName: 'assetName', - sources: sources, - linkerOptions: LinkerOptions.treeshake(symbols: ['my_other_func']), - ); - final linkerAutoEmpty = CLinker.library( - name: 'mylibname', - assetName: 'assetName', - sources: sources, - linkerOptions: LinkerOptions.treeshake(symbols: null), - ); + CLinker linkerManual(List sources) => CLinker.library( + name: 'mylibname', + assetName: '', + sources: sources, + linkerOptions: LinkerOptions.manual( + flags: ['--strip-debug', '-u', 'my_other_func'], + gcSections: true, + linkerScript: Uri.file('test/clinker/testfiles/linker/symbols.lds'), + ), + ); + CLinker linkerAuto(List sources) => CLinker.library( + name: 'mylibname', + assetName: '', + sources: sources, + linkerOptions: LinkerOptions.treeshake(symbols: ['my_other_func']), + ); + CLinker linkerAutoEmpty(List sources) => CLinker.library( + name: 'mylibname', + assetName: '', + sources: sources, + linkerOptions: LinkerOptions.treeshake(symbols: null), + ); const architecture = Architecture.x64; const os = OS.linux; @@ -63,6 +60,8 @@ void main() { ]) { test('link test with CLinker ${clinker.name}', () async { final tempUri = await tempDirForTest(); + final testArchive = await buildTestArchive(tempUri); + final linkOutput = LinkOutput(); final config = LinkConfig.build( @@ -76,7 +75,7 @@ void main() { cCompiler: compilerConfig, assets: [], ); - await clinker.linker.run( + await clinker.linker([testArchive.toFilePath()]).run( config: config, output: linkOutput, logger: logger, @@ -113,12 +112,7 @@ void main() { Future<(String, int)> elfAndSize(LinkOutput linkOutput) async { final filePath = linkOutput.assets.first.file!.toFilePath(); - final readelf = (await runProcess( - executable: Uri.file('readelf'), - arguments: ['-WCs', filePath], - logger: logger, - )) - .stdout; + final readelf = await executeReadelf(filePath); final du = Process.runSync('du', ['-sb', filePath]).stdout as String; final sizeInBytes = int.parse(du.split('\t')[0]); diff --git a/pkgs/native_toolchain_c/test/helpers.dart b/pkgs/native_toolchain_c/test/helpers.dart index 612c2f087..8fa590110 100644 --- a/pkgs/native_toolchain_c/test/helpers.dart +++ b/pkgs/native_toolchain_c/test/helpers.dart @@ -184,3 +184,14 @@ DynamicLibrary openDynamicLibraryForTest(String path) { extension UnescapePath on String { String unescape() => replaceAll('\\', '/'); } + +Future executeReadelf(String filePath) async { + final result = await runProcess( + executable: Uri.file('readelf'), + arguments: ['-WCs', filePath], + logger: logger, + ); + + expect(result.exitCode, 0); + return result.stdout; +}