Skip to content

Commit be73de7

Browse files
authored
[native_assets_*] Error on conflict dylib names (#1512)
1 parent b18d32f commit be73de7

File tree

12 files changed

+213
-5
lines changed

12 files changed

+213
-5
lines changed

.github/workflows/native.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ jobs:
6363
- run: dart pub get -C test_data/native_add/
6464
if: ${{ matrix.package == 'native_assets_builder' }}
6565

66+
- run: dart pub get -C test_data/native_add_duplicate/
67+
if: ${{ matrix.package == 'native_assets_builder' }}
68+
6669
- run: dart pub get -C test_data/native_add_v1_0_0/
6770
if: ${{ matrix.package == 'native_assets_builder' }}
6871

pkgs/native_assets_builder/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 0.8.3-wip
22

3-
- Added a validation step on the output of the build and link hooks.
3+
- Added a validation step on the output of the build and link hooks (both as a
4+
per package, and as in all the packages together).
45

56
## 0.8.2
67

pkgs/native_assets_builder/lib/src/build_runner/build_runner.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,16 @@ class NativeAssetsBuildRunner {
215215
metadata[config.packageName] = hookOutput.metadata;
216216
}
217217

218+
// Note the caller will need to check whether there are no duplicates
219+
// between the build and link hook.
220+
final validateResult = validateNoDuplicateDylibs(hookResult.assets);
221+
if (validateResult.isNotEmpty) {
222+
for (final error in validateResult) {
223+
logger.severe(error);
224+
}
225+
hookResult = hookResult.copyAdd(HookOutputImpl(), false);
226+
}
227+
218228
return hookResult;
219229
}
220230

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:logging/logging.dart';
6+
import 'package:test/test.dart';
7+
8+
import '../helpers.dart';
9+
import 'helpers.dart';
10+
11+
const Timeout longTimeout = Timeout(Duration(minutes: 5));
12+
13+
void main() async {
14+
test('conflicting dylib name', timeout: longTimeout, () async {
15+
await inTempDir((tempUri) async {
16+
await copyTestProjects(targetUri: tempUri);
17+
final packageUri = tempUri.resolve('native_add_duplicate/');
18+
19+
await runPubGet(
20+
workingDirectory: packageUri,
21+
logger: logger,
22+
);
23+
24+
{
25+
final logMessages = <String>[];
26+
final result = await build(
27+
packageUri,
28+
createCapturingLogger(logMessages, level: Level.SEVERE),
29+
dartExecutable,
30+
);
31+
final fullLog = logMessages.join('\n');
32+
expect(result.success, false);
33+
expect(
34+
fullLog,
35+
contains('Duplicate dynamic library file name'),
36+
);
37+
}
38+
});
39+
});
40+
}

pkgs/native_assets_builder/test_data/manifest.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@
6363
- native_add/src/native_add.c
6464
- native_add/src/native_add.h
6565
- native_add/test/native_add_test.dart
66+
- native_add_duplicate/hook/build.dart
67+
- native_add_duplicate/pubspec.yaml
68+
- native_add_duplicate/src/native_add.c
69+
- native_add_duplicate/src/native_add.h
6670
- native_subtract/ffigen.yaml
6771
- native_subtract/hook/build.dart
6872
- native_subtract/lib/native_subtract.dart
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:logging/logging.dart';
6+
import 'package:native_assets_cli/native_assets_cli.dart';
7+
import 'package:native_toolchain_c/native_toolchain_c.dart';
8+
9+
void main(List<String> arguments) async {
10+
await build(arguments, (config, output) async {
11+
final packageName = config.packageName;
12+
const duplicatedPackageName = 'native_add';
13+
final cbuilder = CBuilder.library(
14+
name: duplicatedPackageName,
15+
assetName: 'src/${packageName}_bindings_generated.dart',
16+
sources: [
17+
'src/$duplicatedPackageName.c',
18+
],
19+
);
20+
await cbuilder.run(
21+
config: config,
22+
output: output,
23+
logger: Logger('')
24+
..level = Level.ALL
25+
..onRecord.listen((record) {
26+
print('${record.level.name}: ${record.time}: ${record.message}');
27+
}),
28+
);
29+
});
30+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: native_add_duplicate
2+
description: Introduces the same dylib as native_add, to introduce a conflict.
3+
version: 0.1.0
4+
5+
publish_to: none
6+
7+
environment:
8+
sdk: '>=3.3.0 <4.0.0'
9+
10+
dependencies:
11+
logging: ^1.1.1
12+
native_add:
13+
path: ../native_add/
14+
# native_assets_cli: ^0.7.3
15+
native_assets_cli:
16+
path: ../../../native_assets_cli/
17+
# native_toolchain_c: ^0.5.3
18+
native_toolchain_c:
19+
path: ../../../native_toolchain_c/
20+
21+
dev_dependencies:
22+
ffigen: ^8.0.2
23+
lints: ^3.0.0
24+
some_dev_dep:
25+
path: ../some_dev_dep/
26+
test: ^1.23.1
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
#include "native_add.h"
6+
7+
int32_t add(int32_t a, int32_t b) {
8+
return a + b;
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
#include <stdint.h>
6+
7+
#if _WIN32
8+
#define MYLIB_EXPORT __declspec(dllexport)
9+
#else
10+
#define MYLIB_EXPORT
11+
#endif
12+
13+
MYLIB_EXPORT int32_t add(int32_t a, int32_t b);

pkgs/native_assets_cli/lib/native_assets_cli_internal.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,4 @@ export 'src/model/metadata.dart';
4242
export 'src/model/resource_identifiers.dart';
4343
export 'src/model/target.dart';
4444
export 'src/validator/validator.dart'
45-
show ValidateResult, validateBuild, validateLink;
45+
show ValidateResult, validateBuild, validateLink, validateNoDuplicateDylibs;

pkgs/native_assets_cli/lib/src/validator/validator.dart

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ typedef ValidateResult = ({
1616
List<String> errors,
1717
});
1818

19-
// TODO(dacoharkes): More validation in the native_assets_builder.
20-
// TODO(dacoharkes): NativeCodeAssets and DataAssets should have a file if not
21-
// dry run.
2219
Future<ValidateResult> validateBuild(
2320
BuildConfig config,
2421
BuildOutput output,
@@ -31,6 +28,7 @@ Future<ValidateResult> validateBuild(
3128
...validateNativeCodeAssets(config, output),
3229
...validateAssetId(config, output),
3330
if (!config.dryRun) ...validateNoDuplicateAssetIds(output),
31+
...validateNoDuplicateDylibs(output.assets),
3432
];
3533
return (
3634
success: errors.isEmpty,
@@ -48,6 +46,7 @@ Future<ValidateResult> validateLink(
4846
if (!config.dryRun) ...await validateFilesExist(config, output),
4947
...validateNativeCodeAssets(config, output),
5048
if (!config.dryRun) ...validateNoDuplicateAssetIds(output),
49+
...validateNoDuplicateDylibs(output.assets),
5150
];
5251

5352
return (
@@ -205,3 +204,33 @@ List<String> validateNoDuplicateAssetIds(
205204
}
206205
return errors;
207206
}
207+
208+
List<String> validateNoDuplicateDylibs(
209+
Iterable<Asset> assets,
210+
) {
211+
final errors = <String>[];
212+
final fileNameToAssetId = <String, Set<String>>{};
213+
for (final asset in assets.whereType<NativeCodeAsset>()) {
214+
if (asset.linkMode is! DynamicLoadingBundled) {
215+
continue;
216+
}
217+
final file = asset.file;
218+
if (file == null) {
219+
continue;
220+
}
221+
final fileName = file.pathSegments.where((s) => s.isNotEmpty).last;
222+
fileNameToAssetId[fileName] ??= {};
223+
fileNameToAssetId[fileName]!.add(asset.id);
224+
}
225+
for (final fileName in fileNameToAssetId.keys) {
226+
final assetIds = fileNameToAssetId[fileName]!;
227+
if (assetIds.length > 1) {
228+
final assetIdsString = assetIds.map((e) => '"$e"').join(', ');
229+
final error =
230+
'Duplicate dynamic library file name "$fileName" for the following'
231+
' asset ids: $assetIdsString.';
232+
errors.add(error);
233+
}
234+
}
235+
return errors;
236+
}

pkgs/native_assets_cli/test/validator/validator_test.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,4 +392,47 @@ void main() {
392392
contains(contains('which is not in supportedAssetTypes')),
393393
);
394394
});
395+
396+
test('duplicate dylib name', () async {
397+
final config = BuildConfig.build(
398+
outputDirectory: outDirUri,
399+
packageName: packageName,
400+
packageRoot: tempUri,
401+
targetArchitecture: Architecture.arm64,
402+
targetOS: OS.iOS,
403+
targetIOSSdk: IOSSdk.iPhoneOS,
404+
buildMode: BuildMode.release,
405+
linkModePreference: LinkModePreference.dynamic,
406+
supportedAssetTypes: [NativeCodeAsset.type],
407+
linkingEnabled: false,
408+
);
409+
final output = BuildOutput();
410+
final fileName = config.targetOS.dylibFileName('foo');
411+
final assetFile = File.fromUri(outDirUri.resolve(fileName));
412+
await assetFile.writeAsBytes([1, 2, 3]);
413+
output.addAssets([
414+
NativeCodeAsset(
415+
package: config.packageName,
416+
name: 'src/foo.dart',
417+
file: assetFile.uri,
418+
linkMode: DynamicLoadingBundled(),
419+
os: config.targetOS,
420+
architecture: config.targetArchitecture,
421+
),
422+
NativeCodeAsset(
423+
package: config.packageName,
424+
name: 'src/bar.dart',
425+
file: assetFile.uri,
426+
linkMode: DynamicLoadingBundled(),
427+
os: config.targetOS,
428+
architecture: config.targetArchitecture,
429+
),
430+
]);
431+
final result = await validateBuild(config, output);
432+
expect(result.success, isFalse);
433+
expect(
434+
result.errors,
435+
contains(contains('Duplicate dynamic library file name')),
436+
);
437+
});
395438
}

0 commit comments

Comments
 (0)