mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Merge pull request #8628 from roc-lang/improve-bundle
Add `--whole-archive` for WASM and improve `roc bundle`
This commit is contained in:
commit
85b6a0fb9f
3 changed files with 67 additions and 20 deletions
|
|
@ -324,11 +324,23 @@ pub fn link(allocs: *Allocators, config: LinkConfig) LinkError!void {
|
|||
},
|
||||
}
|
||||
|
||||
// For WASM targets, wrap platform files in --whole-archive to include all symbols
|
||||
// This ensures host exports (init, handleEvent, update) aren't stripped even when
|
||||
// not referenced by other code
|
||||
const is_wasm = config.target_format == .wasm;
|
||||
if (is_wasm and config.platform_files_pre.len > 0) {
|
||||
try args.append("--whole-archive");
|
||||
}
|
||||
|
||||
// Add platform-provided files that come before object files
|
||||
for (config.platform_files_pre) |platform_file| {
|
||||
try args.append(platform_file);
|
||||
}
|
||||
|
||||
if (is_wasm and config.platform_files_pre.len > 0) {
|
||||
try args.append("--no-whole-archive");
|
||||
}
|
||||
|
||||
// Add object files
|
||||
for (config.object_files) |obj_file| {
|
||||
try args.append(obj_file);
|
||||
|
|
|
|||
|
|
@ -3271,11 +3271,23 @@ pub fn rocBundle(allocs: *Allocators, args: cli_args.BundleArgs) !void {
|
|||
}
|
||||
}
|
||||
|
||||
// Validate platform header if the first file looks like a platform
|
||||
// This ensures bundles have proper targets sections
|
||||
const main_file = file_paths.items[0];
|
||||
if (std.mem.endsWith(u8, main_file, ".roc")) {
|
||||
if (platform_validation.validatePlatformHeader(allocs.arena, main_file)) |validation| {
|
||||
// Find the platform file among the .roc files (if any)
|
||||
// We need to check each file without side effects first, then validate the actual platform
|
||||
var platform_file: ?[]const u8 = null;
|
||||
for (file_paths.items) |path| {
|
||||
if (std.mem.endsWith(u8, path, ".roc")) {
|
||||
if (platform_validation.isPlatformFile(allocs.arena, path)) |is_platform| {
|
||||
if (is_platform) {
|
||||
platform_file = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a platform file, validate it has proper targets section
|
||||
if (platform_file) |pf| {
|
||||
if (platform_validation.validatePlatformHeader(allocs.arena, pf)) |validation| {
|
||||
// Platform validation succeeded - validate all target files exist
|
||||
if (platform_validation.validateAllTargetFilesExist(
|
||||
allocs.arena,
|
||||
|
|
@ -3290,21 +3302,10 @@ pub fn rocBundle(allocs: *Allocators, args: cli_args.BundleArgs) !void {
|
|||
else => error.MissingTargetFile,
|
||||
};
|
||||
}
|
||||
std.log.debug("Platform validation passed for: {s}", .{main_file});
|
||||
} else |err| {
|
||||
switch (err) {
|
||||
error.MissingTargetsSection => {
|
||||
// Only warn - file might be an app, not a platform
|
||||
std.log.debug("File {s} has no targets section (may be an app)", .{main_file});
|
||||
},
|
||||
error.ParseError, error.FileReadError => {
|
||||
// Parsing failed - could be invalid syntax or not a Roc file
|
||||
std.log.debug("Could not parse {s} as platform: {}", .{ main_file, err });
|
||||
},
|
||||
else => {
|
||||
std.log.warn("Platform validation warning: {}", .{err});
|
||||
},
|
||||
}
|
||||
} else |_| {
|
||||
// validatePlatformHeader already rendered the error message via the reporting system.
|
||||
// We continue bundling for now (non-blocking warning), but the user has seen the error.
|
||||
// This allows bundling apps or platforms that don't yet have targets sections.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,40 @@ pub const PlatformValidation = struct {
|
|||
platform_dir: []const u8,
|
||||
};
|
||||
|
||||
/// Check if a file is a platform header (has `platform` at the start).
|
||||
/// This is a quick check without side effects - useful for finding which file
|
||||
/// in a set of .roc files is the actual platform file.
|
||||
/// Returns true if the file is a platform, false if it's a module/app, or null on error.
|
||||
pub fn isPlatformFile(
|
||||
allocator: std.mem.Allocator,
|
||||
source_path: []const u8,
|
||||
) ?bool {
|
||||
// Read source file
|
||||
const source = std.fs.cwd().readFileAlloc(allocator, source_path, std.math.maxInt(usize)) catch {
|
||||
return null;
|
||||
};
|
||||
defer allocator.free(source);
|
||||
|
||||
// Initialize parse environment
|
||||
var env = base.CommonEnv.init(allocator, source) catch {
|
||||
return null;
|
||||
};
|
||||
|
||||
// Parse the file
|
||||
const ast = parse.parse(&env, allocator) catch {
|
||||
return null;
|
||||
};
|
||||
|
||||
// Check the header type
|
||||
const file = ast.store.getFile();
|
||||
const header = ast.store.getHeader(file.header);
|
||||
|
||||
return switch (header) {
|
||||
.platform => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// Parse and validate a platform header.
|
||||
/// Returns the TargetsConfig if valid, or an error with details.
|
||||
pub fn validatePlatformHeader(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue