Changed generate.dart script to dynamically look for needed files for linux/windows/macos with newest version

This commit is contained in:
istalri 2026-05-29 09:31:14 +02:00
commit de97890634

View file

@ -4,8 +4,7 @@ import "package:path/path.dart" as path;
void main(List<String> args) async { void main(List<String> args) async {
final Directory repoDir = Directory.fromUri(Platform.script.resolve("../gomuks")); final Directory repoDir = Directory.fromUri(Platform.script.resolve("../gomuks"));
print("Generating FFI Bindings for ${Platform.operatingSystem}...");
print("Generating FFI Bindings...");
int? parseVersion(String name) { int? parseVersion(String name) {
final RegExpMatch? match = RegExp(r"^(\d+)(?:\.(\d+))?(?:\.(\d+))?$").firstMatch(name); final RegExpMatch? match = RegExp(r"^(\d+)(?:\.(\d+))?(?:\.(\d+))?$").firstMatch(name);
@ -17,63 +16,145 @@ void main(List<String> args) async {
final int major = int.tryParse(match.group(1)!) ?? 0; final int major = int.tryParse(match.group(1)!) ?? 0;
final int minor = int.tryParse(match.group(2) ?? "0") ?? 0; final int minor = int.tryParse(match.group(2) ?? "0") ?? 0;
final int patch = int.tryParse(match.group(3) ?? "0") ?? 0; final int patch = int.tryParse(match.group(3) ?? "0") ?? 0;
return major * 10000 + minor * 100 + patch; //Single number to compare versions based on integer math return major * 10000 + minor * 100 + patch;
} }
final List<String> systemIncludePaths = [];
late String targetTriple;
late String libclangName;
if (Platform.isLinux) {
targetTriple = "x86_64-pc-linux-gnu";
libclangName = "libclang.so";
final Directory gccBaseDir = Directory("/usr/lib/gcc/x86_64-pc-linux-gnu"); final Directory gccBaseDir = Directory("/usr/lib/gcc/x86_64-pc-linux-gnu");
String? latestGccIncludePath;
if (await gccBaseDir.exists()) { if (await gccBaseDir.exists()) {
final Iterable<Directory> entries = gccBaseDir.listSync().whereType<Directory>(); final List<Directory> dirs = gccBaseDir.listSync().whereType<Directory>().toList();
final List<Directory> versionDirs = entries.where((dir) { dirs.sort((a, b) {
final String name = path.basename(dir.path); final int va = parseVersion(path.basename(a.path)) ?? 0;
return parseVersion(name) != null; final int vb = parseVersion(path.basename(b.path)) ?? 0;
}).toList(); return vb.compareTo(va);
if (versionDirs.isNotEmpty) {
versionDirs.sort((a, b) {
final int verA = parseVersion(path.basename(a.path))!;
final int verB = parseVersion(path.basename(b.path))!;
return verB.compareTo(verA); // Descending
}); });
final Directory latestDir = versionDirs.first; if (dirs.isNotEmpty) {
latestGccIncludePath = path.join(latestDir.path, "include"); final Directory latest = dirs.first;
print("Successfully detected GCC version: ${path.basename(latestDir.path)} -> Using: $latestGccIncludePath"); final String inc = path.join(latest.path, "include");
} else { systemIncludePaths.add(inc);
print("!Warning!: No GCC version directories found in ${gccBaseDir.path}"); systemIncludePaths.add(path.dirname(inc));
print("Using GCC: ${path.basename(latest.path)}");
} }
} else {
print("!Warning!: GCC base directory not found at ${gccBaseDir.path}");
}
final List<String> systemIncludePaths = <String>[];
if (latestGccIncludePath != null) {
systemIncludePaths.add(latestGccIncludePath);
systemIncludePaths.add(path.dirname(latestGccIncludePath));
} }
final Directory clangDir = Directory("/usr/lib/clang"); final Directory clangDir = Directory("/usr/lib/clang");
if (await clangDir.exists()) { if (await clangDir.exists()) {
final List<Directory> clangEntries = clangDir.listSync().whereType<Directory>().toList(); final List<Directory> dirs = clangDir.listSync().whereType<Directory>().toList();
if (clangEntries.isNotEmpty) { dirs.sort((a, b) {
clangEntries.sort((a, b) { final int va = parseVersion(path.basename(a.path)) ?? 0;
final verA = parseVersion(path.basename(a.path)) ?? 0; final int vb = parseVersion(path.basename(b.path)) ?? 0;
final verB = parseVersion(path.basename(b.path)) ?? 0; return vb.compareTo(va);
return verB.compareTo(verA);
}); });
systemIncludePaths.add(path.join(clangEntries.first.path, "include"));
if (dirs.isNotEmpty) {
systemIncludePaths.add(path.join(dirs.first.path, "include"));
} }
} }
//Standard Paths systemIncludePaths.addAll(["/usr/include", "/usr/include/x86_64-linux-gnu", "/usr/local/include"]);
systemIncludePaths.addAll([
"/usr/include", } else if (Platform.isMacOS) {
"/usr/include/x86_64-linux-gnu", final String arch = _detectMacArch();
"/usr/local/include", targetTriple = "$arch-apple-darwin";
]); libclangName = "libclang.dylib";
final String? sdkPath = _runCommand("xcrun", ["--show-sdk-path"]);
if (sdkPath != null) {
systemIncludePaths.add(path.join(sdkPath, "usr", "include"));
print("Using Xcode SDK: $sdkPath");
}
final String? clangResDir = _runCommand("clang", ["-print-resource-dir"]);
if (clangResDir != null) {
final String inc = path.join(clangResDir, "include");
if (Directory(inc).existsSync()) {
systemIncludePaths.add(inc);
}
}
final String brewPrefix = arch == "arm64" ? "/opt/homebrew" : "/usr/local";
final Directory brewGcc = Directory(path.join(brewPrefix, "opt", "gcc", "lib", "gcc", "current", "include"));
if (brewGcc.existsSync()) {
systemIncludePaths.add(brewGcc.path);
print("Using Homebrew GCC");
}
systemIncludePaths.addAll(["$brewPrefix/include", "/usr/local/include"]);
} else if (Platform.isWindows) {
targetTriple = "x86_64-pc-windows-msvc";
libclangName = "libclang.dll";
final String vswhere = r"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe";
final String? vsPath = _runCommand(vswhere, ["-latest", "-property", "installationPath"]);
if (vsPath != null) {
final Directory msvcDir = Directory(path.join(vsPath, "VC", "Tools", "MSVC"));
if (msvcDir.existsSync()) {
final List<Directory> dirs = msvcDir.listSync().whereType<Directory>().toList();
dirs.sort((a, b) {
final int va = parseVersion(path.basename(a.path)) ?? 0;
final int vb = parseVersion(path.basename(b.path)) ?? 0;
return vb.compareTo(va);
});
if (dirs.isNotEmpty) {
systemIncludePaths.add(path.join(dirs.first.path, "include"));
print("Using MSVC: ${path.basename(dirs.first.path)}");
}
}
}
final Directory sdkDir = Directory(r"C:\Program Files (x86)\Windows Kits\10\Include");
if (sdkDir.existsSync()) {
final List<Directory> dirs = sdkDir.listSync().whereType<Directory>().toList();
dirs.sort((a, b) {
final int va = parseVersion(path.basename(a.path)) ?? 0;
final int vb = parseVersion(path.basename(b.path)) ?? 0;
return vb.compareTo(va);
});
if (dirs.isNotEmpty) {
final String sdkVer = dirs.first.path;
for (final String sub in ["um", "ucrt", "shared"]) {
final String p = path.join(sdkVer, sub);
if (Directory(p).existsSync()) systemIncludePaths.add(p);
}
print("Using Windows SDK: ${path.basename(sdkVer)}");
}
}
final Directory llvmDir = Directory(r"C:\Program Files\LLVM\include");
if (llvmDir.existsSync()) {
systemIncludePaths.add(llvmDir.path);
}
} else {
print("Error: Unsupported platform: ${Platform.operatingSystem}");
exit(1);
}
print("Target: $targetTriple");
print("Include paths: ${systemIncludePaths.length} found");
final String? libclangPath = Platform.environment["LIBCLANG_PATH"]; final String? libclangPath = Platform.environment["LIBCLANG_PATH"];
@ -85,16 +166,30 @@ void main(List<String> args) async {
entryPoints: [File(path.join(repoDir.path, "pkg", "ffi", "gomuksffi.h")).uri], entryPoints: [File(path.join(repoDir.path, "pkg", "ffi", "gomuksffi.h")).uri],
compilerOptions: [ compilerOptions: [
"--no-warnings", "--no-warnings",
"-target", "x86_64-pc-linux-gnu", "-target", targetTriple,
...systemIncludePaths.map((path) => "-I$path"), ...systemIncludePaths.map((p) => "-I$p"),
], ],
), ),
functions: Functions.includeAll, functions: Functions.includeAll,
).generate( ).generate(
libclangDylib: libclangPath == null libclangDylib: libclangPath == null
? null ? null
: Uri.file(path.join(libclangPath, "libclang.so")), : Uri.file(path.join(libclangPath, libclangName)),
); );
print("Done!"); print("Done!");
} }
String _detectMacArch() {
final String? res = _runCommand("uname", ["-m"]);
return res?.trim() == "arm64" ? "arm64" : "x86_64";
}
String? _runCommand(String exe, List<String> args) {
try {
final ProcessResult res = Process.runSync(exe, args);
return res.exitCode == 0 ? (res.stdout as String).trim() : null;
} catch (_) {
return null;
}
}