Skip to content

Commit

Permalink
Add includes, flags, std, language, cppLinkStdLib options (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
blaugold authored Sep 14, 2023
1 parent bbcbc1f commit 7faf62c
Show file tree
Hide file tree
Showing 20 changed files with 1,061 additions and 629 deletions.
8 changes: 8 additions & 0 deletions pkgs/native_toolchain_c/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 0.2.4

- Added `includes` for specifying include directories.
- Added `flags` for specifying arbitrary compiler flags.
- Added `std` for specifying a language standard.
- Added `language` for selecting the language (`c` and `cpp`) to compile source files as.
- Added `cppLinkStdLib` for specifying the C++ standard library to link against.

## 0.2.3

- Fix MSVC tool resolution inside (x86) folder
Expand Down
91 changes: 89 additions & 2 deletions pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ abstract class Builder {
});
}

/// 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++');

/// Known values for [Language].
static const List<Language> values = [c, cpp];

@override
String toString() => name;
}

/// Specification for building an artifact with a C compiler.
class CBuilder implements Builder {
/// What kind of artifact to build.
Expand Down Expand Up @@ -45,6 +64,13 @@ class CBuilder implements Builder {
/// Used to output the [BuildOutput.dependencies].
final List<String> sources;

/// Include directories to pass to the compiler.
///
/// Resolved against [BuildConfig.packageRoot].
///
/// Used to output the [BuildOutput.dependencies].
final List<String> includes;

/// The dart files involved in building this artifact.
///
/// Resolved against [BuildConfig.packageRoot].
Expand All @@ -57,6 +83,9 @@ class CBuilder implements Builder {
@visibleForTesting
final Uri? installName;

/// Flags to pass to the compiler.
final List<String> flags;

/// Definitions of preprocessor macros.
///
/// When the value is `null`, the macro is defined without a value.
Expand Down Expand Up @@ -95,26 +124,64 @@ class CBuilder implements Builder {
/// 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
/// [Langauge.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;

CBuilder.library({
required this.name,
required this.assetId,
this.sources = const [],
this.includes = const [],
this.dartBuildFiles = const ['build.dart'],
@visibleForTesting this.installName,
this.flags = const [],
this.defines = const {},
this.buildModeDefine = true,
this.ndebugDefine = true,
this.pic = true,
this.std,
this.language = Language.c,
this.cppLinkStdLib,
}) : _type = _CBuilderType.library;

CBuilder.executable({
required this.name,
this.sources = const [],
this.includes = const [],
this.dartBuildFiles = const ['build.dart'],
this.flags = const [],
this.defines = const {},
this.buildModeDefine = true,
this.ndebugDefine = true,
bool? pie = false,
this.std,
this.language = Language.c,
this.cppLinkStdLib,
}) : _type = _CBuilderType.executable,
assetId = null,
installName = null,
Expand All @@ -141,6 +208,10 @@ class CBuilder implements Builder {
for (final source in this.sources)
packageRoot.resolveUri(Uri.file(source)),
];
final includes = [
for (final directory in this.includes)
packageRoot.resolveUri(Uri.file(directory)),
];
final dartBuildFiles = [
for (final source in this.dartBuildFiles) packageRoot.resolve(source),
];
Expand All @@ -149,6 +220,7 @@ class CBuilder implements Builder {
buildConfig: buildConfig,
logger: logger,
sources: sources,
includes: includes,
dynamicLibrary:
_type == _CBuilderType.library && linkMode == LinkMode.dynamic
? libUri
Expand All @@ -159,13 +231,17 @@ class CBuilder implements Builder {
: null,
executable: _type == _CBuilderType.executable ? exeUri : null,
installName: installName,
flags: flags,
defines: {
...defines,
if (buildModeDefine) buildConfig.buildMode.name.toUpperCase(): null,
if (ndebugDefine && buildConfig.buildMode != BuildMode.debug)
'NDEBUG': null,
},
pic: pic,
std: std,
language: language,
cppLinkStdLib: cppLinkStdLib,
);
await task.run();
}
Expand All @@ -188,10 +264,21 @@ class CBuilder implements Builder {
}
}
if (!buildConfig.dryRun) {
buildOutput.dependencies.dependencies.addAll([
final includeFiles = await Stream.fromIterable(includes)
.asyncExpand(
(include) => Directory(include.toFilePath())
.list(recursive: true)
.where((entry) => entry is File)
.map((file) => file.uri),
)
.toList();

buildOutput.dependencies.dependencies.addAll({
// Note: We use a Set here to deduplicate the dependencies.
...sources,
...includeFiles,
...dartBuildFiles,
]);
});
}
}
}
Expand Down
70 changes: 55 additions & 15 deletions pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ 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';

class RunCBuilder {
final BuildConfig buildConfig;
final Logger? logger;
final List<Uri> sources;
final List<Uri> includes;
final Uri? executable;
final Uri? dynamicLibrary;
final Uri? staticLibrary;
Expand All @@ -32,25 +34,42 @@ class RunCBuilder {
/// Can be modified with `install_name_tool`.
final Uri? installName;

final List<String> flags;
final Map<String, String?> defines;
final bool? pic;
final String? std;
final Language language;
final String? cppLinkStdLib;

RunCBuilder({
required this.buildConfig,
this.logger,
this.sources = const [],
this.includes = const [],
this.executable,
this.dynamicLibrary,
this.staticLibrary,
this.installName,
this.flags = const [],
this.defines = const {},
this.pic,
this.std,
this.language = Language.c,
this.cppLinkStdLib,
}) : outDir = buildConfig.outDir,
target = buildConfig.target,
assert([executable, dynamicLibrary, staticLibrary]
.whereType<Uri>()
.length ==
1);
1) {
if (target.os == OS.windows && cppLinkStdLib != null) {
throw ArgumentError.value(
cppLinkStdLib,
'cppLinkStdLib',
'is not supported when targeting Windows',
);
}
}

late final _resolver =
CompilerResolver(buildConfig: buildConfig, logger: logger);
Expand Down Expand Up @@ -133,20 +152,6 @@ class RunCBuilder {
'-install_name',
installName!.toFilePath(),
],
...sources.map((e) => e.toFilePath()),
if (executable != null) ...[
'-o',
outDir.resolveUri(executable!).toFilePath(),
],
if (dynamicLibrary != null) ...[
'--shared',
'-o',
outDir.resolveUri(dynamicLibrary!).toFilePath(),
] else if (staticLibrary != null) ...[
'-c',
'-o',
outDir.resolve('out.o').toFilePath(),
],
if (pic != null)
if (pic!) ...[
if (dynamicLibrary != null) '-fPIC',
Expand All @@ -165,8 +170,31 @@ class RunCBuilder {
'notext',
]
],
if (std != null) '-std=$std',
if (language == Language.cpp) ...[
'-x',
'c++',
'-l',
cppLinkStdLib ?? defaultCppLinkStdLib[target.os]!
],
...flags,
for (final MapEntry(key: name, :value) in defines.entries)
if (value == null) '-D$name' else '-D$name=$value',
for (final include in includes) '-I${include.toFilePath()}',
...sources.map((e) => e.toFilePath()),
if (executable != null) ...[
'-o',
outDir.resolveUri(executable!).toFilePath(),
],
if (dynamicLibrary != null) ...[
'--shared',
'-o',
outDir.resolveUri(dynamicLibrary!).toFilePath(),
] else if (staticLibrary != null) ...[
'-c',
'-o',
outDir.resolve('out.o').toFilePath(),
],
],
logger: logger,
captureOutput: false,
Expand Down Expand Up @@ -201,8 +229,12 @@ class RunCBuilder {
final result = await runProcess(
executable: compiler.uri,
arguments: [
if (std != null) '/std:$std',
if (language == Language.cpp) '/TP',
...flags,
for (final MapEntry(key: name, :value) in defines.entries)
if (value == null) '/D$name' else '/D$name=$value',
for (final directory in includes) '/I${directory.toFilePath()}',
if (executable != null) ...[
...sources.map((e) => e.toFilePath()),
'/link',
Expand Down Expand Up @@ -265,4 +297,12 @@ class RunCBuilder {
IOSSdk.iPhoneSimulator: 'x86_64-apple-ios-simulator',
},
};

static const defaultCppLinkStdLib = {
OS.android: 'c++_shared',
OS.fuchsia: 'c++',
OS.iOS: 'c++',
OS.linux: 'stdc++',
OS.macOS: 'c++',
};
}
4 changes: 2 additions & 2 deletions pkgs/native_toolchain_c/lib/src/native_toolchain/xcode.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ class XCodeSdkResolver implements ToolResolver {
}
assert(result.exitCode == 0);
final uriSymbolic = Uri.directory(result.stdout.trim());
logger?.fine('Found $sdk at ${uriSymbolic.toFilePath()}}');
logger?.fine('Found $sdk at ${uriSymbolic.toFilePath()}');
final uri = Uri.directory(
await Directory.fromUri(uriSymbolic).resolveSymbolicLinks());
if (uriSymbolic != uri) {
logger?.fine('Found $sdk at ${uri.toFilePath()}}');
logger?.fine('Found $sdk at ${uri.toFilePath()}');
}
assert(await Directory.fromUri(uri).exists());
return [ToolInstance(tool: tool, uri: uri)];
Expand Down
4 changes: 2 additions & 2 deletions pkgs/native_toolchain_c/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: native_toolchain_c
description: >-
A library to invoke the native C compiler installed on the host machine.
version: 0.2.3
version: 0.2.4
repository: https://github.com/dart-lang/native/tree/main/pkgs/native_toolchain_c

topics:
Expand All @@ -12,7 +12,7 @@ topics:
- native-toolchain

environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.1.0 <4.0.0'

dependencies:
cli_config: ^0.1.1
Expand Down
Loading

0 comments on commit 7faf62c

Please sign in to comment.