Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[native_toolchain_c] Add libraries and libraryDirectories options to CTool #1423

Merged
merged 14 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/native.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ jobs:

- run: dart --enable-experiment=native-assets test
working-directory: pkgs/${{ matrix.package }}/example/build/native_dynamic_linking/
if: ${{ matrix.package == 'native_assets_cli' && matrix.sdk == 'dev' && !matrix.breaking-change && matrix.os != 'windows' }}
if: ${{ matrix.package == 'native_assets_cli' && matrix.sdk == 'dev' && !matrix.breaking-change }}

- run: dart --enable-experiment=native-assets test
working-directory: pkgs/${{ matrix.package }}/example/build/native_add_app/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,19 @@ void main(List<String> args) async {
sources: [
'src/math.c',
],
// TODO(https://github.com/dart-lang/native/issues/190): Use specific
// API for linking once available.
flags: config.dynamicLinkingFlags('debug'),
libraries: ['debug'],
),
CBuilder.library(
name: 'add',
assetName: 'add.dart',
sources: [
'src/add.c',
],
// TODO(https://github.com/dart-lang/native/issues/190): Use specific
// API for linking once available.
flags: config.dynamicLinkingFlags('math'),
libraries: ['math'],
)
];

// Note: This builders need to be run sequentially because they depend on
// Note: These builders need to be run sequentially because they depend on
// each others output.
for (final builder in builders) {
await builder.run(
Expand All @@ -53,21 +49,3 @@ void main(List<String> args) async {
}
});
}

extension on BuildConfig {
List<String> dynamicLinkingFlags(String libraryName) => switch (targetOS) {
OS.macOS => [
'-L${outputDirectory.toFilePath()}',
'-l$libraryName',
],
OS.linux => [
r'-Wl,-rpath=$ORIGIN',
'-L${outputDirectory.toFilePath()}',
'-l$libraryName',
],
OS.windows => [
outputDirectory.resolve('$libraryName.lib').toFilePath(),
],
_ => throw UnimplementedError('Unsupported OS: $targetOS'),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,19 @@ void main(List<String> args) async {
sources: [
'src/math.c',
],
// TODO(https://github.com/dart-lang/native/issues/190): Use specific
// API for linking once available.
flags: config.dynamicLinkingFlags('debug'),
libraries: ['debug'],
),
CBuilder.library(
name: 'add',
assetName: 'add.dart',
sources: [
'src/add.c',
],
// TODO(https://github.com/dart-lang/native/issues/190): Use specific
// API for linking once available.
flags: config.dynamicLinkingFlags('math'),
libraries: ['math'],
)
];

// Note: This builders need to be run sequentially because they depend on
// Note: These builders need to be run sequentially because they depend on
// each others output.
for (final builder in builders) {
await builder.run(
Expand All @@ -53,20 +49,3 @@ void main(List<String> args) async {
}
});
}

extension on BuildConfig {
List<String> dynamicLinkingFlags(String libraryName) => switch (targetOS) {
OS.macOS => [
'-L${outputDirectory.toFilePath()}',
'-l$libraryName',
],
OS.linux => [
'-Wl,-rpath=\$ORIGIN/.',
'-L${outputDirectory.toFilePath()}',
'-l$libraryName',
],
// TODO(https://github.com/dart-lang/native/issues/1415): Enable support
// for Windows once linker flags are supported by CBuilder.
_ => throw UnimplementedError('Unsupported OS: $targetOS'),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
'mac-os': Timeout.factor(2),
'windows': Timeout.factor(10),
})
// TODO(https://github.com/dart-lang/native/issues/1415): Enable support
// for Windows once linker flags are supported by CBuilder.
@TestOn('!windows')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if (Platform.isWindows) { on line 20.

library;

import 'dart:convert';
Expand Down
1 change: 1 addition & 0 deletions pkgs/native_toolchain_c/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
https://github.com/dart-lang/native/issues/1611
- Make optimization level configurable. Defaults to `-3s` and `/O3`.
https://github.com/dart-lang/native/issues/1267
- Add `libraries` and `libraryDirectories` to `CTool`.

## 0.6.0

Expand Down
10 changes: 10 additions & 0 deletions pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class CBuilder extends CTool implements Builder {
super.sources = const [],
super.includes = const [],
super.frameworks = CTool.defaultFrameworks,
super.libraries = const [],
super.libraryDirectories = CTool.defaultLibraryDirectories,
@Deprecated(
'Newer Dart and Flutter SDKs automatically add the Dart hook '
'sources as dependencies.',
Expand All @@ -76,6 +78,8 @@ class CBuilder extends CTool implements Builder {
super.sources = const [],
super.includes = const [],
super.frameworks = CTool.defaultFrameworks,
super.libraries = const [],
super.libraryDirectories = CTool.defaultLibraryDirectories,
@Deprecated(
'Newer Dart and Flutter SDKs automatically add the Dart hook '
'sources as dependencies.',
Expand Down Expand Up @@ -132,6 +136,10 @@ class CBuilder extends CTool implements Builder {
// ignore: deprecated_member_use_from_same_package
for (final source in this.dartBuildFiles) packageRoot.resolve(source),
];
final libraryDirectories = [
for (final directory in this.libraryDirectories)
outDir.resolveUri(Uri.file(directory)),
];
// ignore: deprecated_member_use
if (!config.dryRun) {
final task = RunCBuilder(
Expand All @@ -141,6 +149,8 @@ class CBuilder extends CTool implements Builder {
sources: sources,
includes: includes,
frameworks: frameworks,
libraries: libraries,
libraryDirectories: libraryDirectories,
dynamicLibrary:
type == OutputType.library && linkMode == DynamicLoadingBundled()
? libUri
Expand Down
8 changes: 8 additions & 0 deletions pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class CLinker extends CTool implements Linker {
super.sources = const [],
super.includes = const [],
super.frameworks = CTool.defaultFrameworks,
super.libraries = const [],
super.libraryDirectories = CTool.defaultLibraryDirectories,
@visibleForTesting super.installName,
super.flags = const [],
super.defines = const {},
Expand Down Expand Up @@ -68,6 +70,10 @@ class CLinker extends CTool implements Linker {
for (final directory in this.includes)
packageRoot.resolveUri(Uri.file(directory)),
];
final libraryDirectories = [
for (final directory in this.libraryDirectories)
outDir.resolveUri(Uri.file(directory)),
];
final task = RunCBuilder(
config: config,
codeConfig: config.codeConfig,
Expand All @@ -76,6 +82,8 @@ class CLinker extends CTool implements Linker {
sources: sources,
includes: includes,
frameworks: frameworks,
libraries: libraries,
libraryDirectories: libraryDirectories,
dynamicLibrary: linkMode == DynamicLoadingBundled() ? libUri : null,
staticLibrary: linkMode == StaticLinking() ? libUri : null,
// ignore: invalid_use_of_visible_for_testing_member
Expand Down
30 changes: 28 additions & 2 deletions pkgs/native_toolchain_c/lib/src/cbuilder/ctool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:meta/meta.dart';
import 'package:native_assets_cli/code_assets.dart';

import 'cbuilder.dart';
import 'clinker.dart';
import 'language.dart';
import 'optimization_level.dart';
import 'output_type.dart';
Expand All @@ -14,7 +15,7 @@ abstract class CTool {
/// What kind of artifact to build.
final OutputType type;

/// Name of the library or executable to linkg.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build or link

(I believe linkers also inherit from ctool)

/// Name of the library or executable to build.
///
/// The filename will be decided by [LinkConfig.targetOS] and
/// [OSLibraryNaming.libraryFileName] or
Expand Down Expand Up @@ -50,16 +51,39 @@ abstract class CTool {
///
/// Defaults to `['Foundation']`.
///
/// Framworks will not be automatically reported as dependencies of the hook.
/// Frameworks will not be automatically reported as dependencies of the hook.
/// 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
/// report them as dependencies of the hook by calling
/// [BuildOutputBuilder.addDependency] / [LinkOutputBuilder.addDependency]
/// manually.
final List<String> frameworks;

/// The default [frameworks].
static const List<String> defaultFrameworks = ['Foundation'];

/// Libraries to link to.
///
/// In addition to the system default directories, libraries will be searched
/// for in [libraryDirectories].
///
/// If you want to link to a library that was built by another [CBuilder] or
/// [CLinker], either leave the default [libraryDirectories] or include `'.'`
/// in the list.
final List<String> libraries;

/// Directories to search for [libraries], in addition to the system default
/// directories.
///
/// Resolved against [LinkConfig.outputDirectory].
///
/// Defaults to `['.']`, which means the [LinkConfig.outputDirectory] will be
/// searched for libraries.
final List<String> libraryDirectories;

/// The default [libraryDirectories].
static const List<String> defaultLibraryDirectories = ['.'];

/// TODO(https://github.com/dart-lang/native/issues/54): Move to [LinkConfig]
/// or hide in public API.
@visibleForTesting
Expand Down Expand Up @@ -130,6 +154,8 @@ abstract class CTool {
required this.sources,
required this.includes,
required this.frameworks,
required this.libraries,
required this.libraryDirectories,
required this.installName,
required this.flags,
required this.defines,
Expand Down
31 changes: 25 additions & 6 deletions pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class RunCBuilder {
final List<Uri> sources;
final List<Uri> includes;
final List<String> frameworks;
final List<String> libraries;
final List<Uri> libraryDirectories;
final Uri? executable;
final Uri? dynamicLibrary;
final Uri? staticLibrary;
Expand Down Expand Up @@ -56,6 +58,8 @@ class RunCBuilder {
this.sources = const [],
this.includes = const [],
required this.frameworks,
this.libraries = const [],
this.libraryDirectories = const [],
this.executable,
this.dynamicLibrary,
this.staticLibrary,
Expand Down Expand Up @@ -298,8 +302,7 @@ class RunCBuilder {
if (executable != null) ...[
'-o',
outDir.resolveUri(executable!).toFilePath(),
],
if (dynamicLibrary != null) ...[
] else if (dynamicLibrary != null) ...[
'--shared',
'-o',
outFile!.toFilePath(),
Expand All @@ -310,6 +313,19 @@ class RunCBuilder {
],
...linkerOptions?.postSourcesFlags(toolInstance.tool, sourceFiles) ??
[],
if (executable != null || dynamicLibrary != null) ...[
if (config.targetOS case OS.android || OS.linux)
// During bundling code assets are all placed in the same directory.
// Setting this rpath allows the binary to find other code assets
// it is linked against.
if (linkerOptions != null)
'-rpath=\$ORIGIN'
else
'-Wl,-rpath=\$ORIGIN',
for (final directory in libraryDirectories)
'-L${directory.toFilePath()}',
for (final library in libraries) '-l$library',
],
],
logger: logger,
captureOutput: false,
Expand Down Expand Up @@ -344,17 +360,20 @@ class RunCBuilder {
...sources.map((e) => e.toFilePath()),
'/link',
'/out:${outDir.resolveUri(executable!).toFilePath()}',
],
if (dynamicLibrary != null) ...[
] else if (dynamicLibrary != null) ...[
...sources.map((e) => e.toFilePath()),
'/link',
'/DLL',
'/out:${outDir.resolveUri(dynamicLibrary!).toFilePath()}',
],
if (staticLibrary != null) ...[
] else if (staticLibrary != null) ...[
'/c',
...sources.map((e) => e.toFilePath()),
],
if (executable != null || dynamicLibrary != null) ...[
for (final directory in libraryDirectories)
'/LIBPATH:${directory.toFilePath()}',
for (final library in libraries) '$library.lib',
],
],
workingDirectory: outDir,
environment: environment,
Expand Down
Loading
Loading