| // Copyright (c) 2020, 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. |
| |
| /// ======================================================================= |
| /// =============== Build script to generate dyamic library =============== |
| /// ======================================================================= |
| /// This Script effectively calls the following (but user can provide |
| /// command line args which will replace the defaults shown below)- |
| /// |
| /// Linux: |
| /// ``` |
| /// clang -I/usr/lib/llvm-9/include/ -I/usr/lib/llvm-10/include/ -lclang -shared -fpic wrapper.c -o libwrapped_clang.so |
| /// ``` |
| /// MacOS: |
| /// ``` |
| /// clang -I/usr/local/opt/llvm/include/ -L/usr/local/opt/llvm/lib/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ -v -lclang -shared -fpic wrapper.c -o libwrapped_clang.dylib |
| /// ``` |
| /// Windows: |
| /// ``` |
| /// clang -IC:\Progra~1\LLVM\include -LC:\Progra~1\LLVM\lib -llibclang -shared wrapper.c -o wrapped_clang.dll -Wl,/DEF:wrapper.def |
| /// del wrapped_clang.exp |
| /// del wrapped_clang.lib |
| /// ``` |
| /// ======================================================================= |
| /// ======================================================================= |
| /// ======================================================================= |
| |
| import 'dart:io'; |
| import 'package:args/args.dart'; |
| import 'package:meta/meta.dart'; |
| |
| const macOS = 'macos'; |
| const windows = 'windows'; |
| const linux = 'linux'; |
| |
| /// Default platform options. |
| Map<String, Options> platformOptions = { |
| linux: Options( |
| outputfilename: 'libwrapped_clang.so', |
| sharedFlag: '-shared', |
| inputHeader: 'wrapper.c', |
| fPIC: '-fpic', |
| ldLibFlag: '-lclang', |
| headerIncludes: [ |
| '-I/usr/lib/llvm-9/include/', |
| '-I/usr/lib/llvm-10/include/', |
| ], |
| ), |
| windows: Options( |
| outputfilename: 'wrapped_clang.dll', |
| sharedFlag: '-shared', |
| inputHeader: 'wrapper.c', |
| moduleDefPath: '-Wl,/DEF:wrapper.def', |
| ldLibFlag: '-llibclang', |
| headerIncludes: [ |
| r'-IC:\Progra~1\LLVM\include', |
| ], |
| libIncludes: [ |
| r'-LC:\Progra~1\LLVM\lib', |
| ], |
| ), |
| macOS: Options( |
| outputfilename: 'libwrapped_clang.dylib', |
| sharedFlag: '-shared', |
| inputHeader: 'wrapper.c', |
| fPIC: '-fpic', |
| ldLibFlag: '-lclang', |
| headerIncludes: [ |
| '-I/usr/local/opt/llvm/include/', |
| '-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/', |
| ], |
| libIncludes: [ |
| '-L/usr/local/opt/llvm/lib/', |
| ], |
| ), |
| }; |
| |
| void main(List<String> arguments) { |
| print('Building Dynamic Library for libclang wrapper... '); |
| final options = getPlatformOptions(); |
| |
| // Updates header/lib includes in platform options. |
| changeIncludesUsingCmdArgs(arguments, options); |
| |
| // Run clang compiler to generate the dynamic library. |
| final ProcessResult result = runClangProcess(options); |
| printSuccess(result, options); |
| } |
| |
| /// Calls the clang compiler. |
| ProcessResult runClangProcess(Options options) { |
| final result = Process.runSync( |
| 'clang', |
| [ |
| ...options.headerIncludes, |
| ...options.libIncludes, |
| options.ldLibFlag, |
| options.sharedFlag, |
| options.fPIC, |
| options.inputHeader, |
| '-o', |
| options.outputfilename, |
| options.moduleDefPath, |
| '-Wno-nullability-completeness', |
| ], |
| ); |
| return result; |
| } |
| |
| /// Prints success message (or process error if any). |
| void printSuccess(ProcessResult result, Options options) { |
| print(result.stdout); |
| if ((result.stderr as String).isEmpty) { |
| print('Generated file: ${options.outputfilename}'); |
| } else { |
| print(result.stderr); |
| } |
| } |
| |
| ArgResults getArgResults(List<String> args) { |
| final parser = ArgParser(allowTrailingOptions: true); |
| parser.addSeparator( |
| 'Build Script to generate dynamic library used by this package:'); |
| parser.addMultiOption('include-header', |
| abbr: 'I', help: 'Path to header include directories'); |
| parser.addMultiOption('include-lib', |
| abbr: 'L', help: 'Path to library include directories'); |
| parser.addFlag( |
| 'help', |
| abbr: 'h', |
| help: 'prints this usage', |
| negatable: false, |
| ); |
| |
| ArgResults results; |
| try { |
| results = parser.parse(args); |
| |
| if (results.wasParsed('help')) { |
| print(parser.usage); |
| exit(0); |
| } |
| } catch (e) { |
| print(e); |
| print(parser.usage); |
| exit(1); |
| } |
| |
| return results; |
| } |
| |
| /// Use cmd args(if any) to change header/lib include paths. |
| void changeIncludesUsingCmdArgs(List<String> arguments, Options options) { |
| final argResult = getArgResults(arguments); |
| if (argResult.wasParsed('include-header')) { |
| options.headerIncludes = (argResult['include-header'] as List<String>) |
| .map((header) => '-I$header') |
| .toList(); |
| } |
| if (argResult.wasParsed('include-lib')) { |
| options.libIncludes = (argResult['include-lib'] as List<String>) |
| .map((lib) => '-L$lib') |
| .toList(); |
| } |
| } |
| |
| /// Get options based on current platform. |
| Options getPlatformOptions() { |
| if (Platform.isMacOS) { |
| return platformOptions[macOS]; |
| } else if (Platform.isWindows) { |
| return platformOptions[windows]; |
| } else if (Platform.isLinux) { |
| return platformOptions[linux]; |
| } else { |
| throw Exception('Unknown Platform.'); |
| } |
| } |
| |
| /// Hold options which would be passed to clang. |
| class Options { |
| /// Name of dynamic library to generate. |
| final String outputfilename; |
| |
| /// Tells compiler to generate a shared library. |
| final String sharedFlag; |
| |
| /// Flag for generating Position Independant Code (Not used on windows). |
| final String fPIC; |
| |
| /// Input file. |
| final String inputHeader; |
| |
| /// Path to `.def` file containing symbols to export, windows use only. |
| final String moduleDefPath; |
| |
| /// Path to header files. |
| List<String> headerIncludes; |
| |
| /// Path to dynamic/static libraries |
| List<String> libIncludes; |
| |
| /// Linker flag for linking to libclang. |
| final String ldLibFlag; |
| |
| Options({ |
| @required this.outputfilename, |
| @required this.sharedFlag, |
| @required this.inputHeader, |
| @required this.ldLibFlag, |
| this.headerIncludes = const [], |
| this.libIncludes = const [], |
| this.fPIC = '', |
| this.moduleDefPath = '', |
| }); |
| } |