Skip to content

Commit

Permalink
feat(bundler): add --windows-icon, --windows-no-console, fix bun.exe'…
Browse files Browse the repository at this point in the history
…s main icon (#15894)

Co-authored-by: Dylan Conway <[email protected]>
Co-authored-by: Jarred Sumner <[email protected]>
Co-authored-by: Dylan Conway <[email protected]>
  • Loading branch information
4 people authored Dec 20, 2024
1 parent 0c50b0f commit 7b3554f
Show file tree
Hide file tree
Showing 10 changed files with 1,435 additions and 10 deletions.
16 changes: 13 additions & 3 deletions cmake/targets/BuildBun.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,8 @@ file(GLOB BUN_C_SOURCES ${CONFIGURE_DEPENDS}

if(WIN32)
list(APPEND BUN_C_SOURCES ${CWD}/src/bun.js/bindings/windows/musl-memmem.c)
list(APPEND BUN_CXX_SOURCES ${CWD}/src/bun.js/bindings/windows/rescle.cpp)
list(APPEND BUN_CXX_SOURCES ${CWD}/src/bun.js/bindings/windows/rescle-binding.cpp)
endif()

register_repository(
Expand Down Expand Up @@ -650,19 +652,27 @@ if(WIN32)
set(Bun_VERSION_WITH_TAG ${VERSION})
endif()
set(BUN_ICO_PATH ${CWD}/src/bun.ico)
configure_file(${CWD}/src/bun.ico ${CODEGEN_PATH}/bun.ico COPYONLY)
configure_file(
${CWD}/src/windows-app-info.rc
${CODEGEN_PATH}/windows-app-info.rc
@ONLY
)
list(APPEND BUN_CPP_SOURCES ${CODEGEN_PATH}/windows-app-info.rc)
add_custom_command(
OUTPUT ${CODEGEN_PATH}/windows-app-info.res
COMMAND rc.exe /fo ${CODEGEN_PATH}/windows-app-info.res ${CODEGEN_PATH}/windows-app-info.rc
DEPENDS ${CODEGEN_PATH}/windows-app-info.rc ${CODEGEN_PATH}/bun.ico
COMMENT "Adding Windows resource file ${CODEGEN_PATH}/windows-app-info.res with ico in ${CODEGEN_PATH}/bun.ico"
)
set(WINDOWS_RESOURCES ${CODEGEN_PATH}/windows-app-info.res)
endif()

# --- Executable ---

set(BUN_CPP_OUTPUT ${BUILD_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}${bun}${CMAKE_STATIC_LIBRARY_SUFFIX})

if(BUN_LINK_ONLY)
add_executable(${bun} ${BUN_CPP_OUTPUT} ${BUN_ZIG_OUTPUT})
add_executable(${bun} ${BUN_CPP_OUTPUT} ${BUN_ZIG_OUTPUT} ${WINDOWS_RESOURCES})
set_target_properties(${bun} PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(${bun} PRIVATE ${BUN_CPP_OUTPUT})
elseif(BUN_CPP_ONLY)
Expand All @@ -680,7 +690,7 @@ elseif(BUN_CPP_ONLY)
${BUN_CPP_OUTPUT}
)
else()
add_executable(${bun} ${BUN_CPP_SOURCES})
add_executable(${bun} ${BUN_CPP_SOURCES} ${WINDOWS_RESOURCES})
target_link_libraries(${bun} PRIVATE ${BUN_ZIG_OUTPUT})
endif()

Expand Down
13 changes: 13 additions & 0 deletions docs/bundler/executables.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,19 @@ $ bun build --compile --asset-naming="[name].[ext]" ./index.ts

To trim down the size of the executable a little, pass `--minify` to `bun build --compile`. This uses Bun's minifier to reduce the code size. Overall though, Bun's binary is still way too big and we need to make it smaller.

## Windows-specific flags

When compiling a standalone executable on Windows, there are two platform-specific options that can be used to customize metadata on the generated `.exe` file:

- `--windows-icon=path/to/icon.ico` to customize the executable file icon.
- `--windows-hide-console` to disable the background terminal, which can be used for applications that do not need a TTY.

{% callout %}

These flags currently cannot be used when cross-compiling because they depend on Windows APIs.

{% /callout %}

## Unsupported CLI arguments

Currently, the `--compile` flag can only accept a single entrypoint at a time and does not support the following flags:
Expand Down
29 changes: 27 additions & 2 deletions src/StandaloneModuleGraph.zig
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,11 @@ pub const StandaloneModuleGraph = struct {
else
std.mem.page_size;

pub fn inject(bytes: []const u8, self_exe: [:0]const u8) bun.FileDescriptor {
pub const InjectOptions = struct {
windows_hide_console: bool = false,
};

pub fn inject(bytes: []const u8, self_exe: [:0]const u8, inject_options: InjectOptions) bun.FileDescriptor {
var buf: bun.PathBuffer = undefined;
var zname: [:0]const u8 = bun.span(bun.fs.FileSystem.instance.tmpname("bun-build", &buf, @as(u64, @bitCast(std.time.milliTimestamp()))) catch |err| {
Output.prettyErrorln("<r><red>error<r><d>:<r> failed to get temporary file name: {s}", .{@errorName(err)});
Expand Down Expand Up @@ -470,7 +474,7 @@ pub const StandaloneModuleGraph = struct {
bun.invalid_fd,
out,
// access_mask
w.SYNCHRONIZE | w.GENERIC_WRITE | w.DELETE,
w.SYNCHRONIZE | w.GENERIC_WRITE | w.GENERIC_READ | w.DELETE,
// create disposition
w.FILE_OPEN,
// create options
Expand Down Expand Up @@ -637,6 +641,15 @@ pub const StandaloneModuleGraph = struct {
_ = bun.C.fchmod(cloned_executable_fd.int(), 0o777);
}

if (Environment.isWindows and inject_options.windows_hide_console) {
bun.windows.editWin32BinarySubsystem(.{ .handle = cloned_executable_fd }, .windows_gui) catch |err| {
Output.err(err, "failed to disable console on executable", .{});
cleanup(zname, cloned_executable_fd);

Global.exit(1);
};
}

return cloned_executable_fd;
}

Expand Down Expand Up @@ -664,6 +677,8 @@ pub const StandaloneModuleGraph = struct {
outfile: []const u8,
env: *bun.DotEnv.Loader,
output_format: bun.options.Format,
windows_hide_console: bool,
windows_icon: ?[]const u8,
) !void {
const bytes = try toBytes(allocator, module_prefix, output_files, output_format);
if (bytes.len == 0) return;
Expand All @@ -680,6 +695,7 @@ pub const StandaloneModuleGraph = struct {
Output.err(err, "failed to download cross-compiled bun executable", .{});
Global.exit(1);
},
.{ .windows_hide_console = windows_hide_console },
);
fd.assertKind(.system);

Expand All @@ -704,6 +720,15 @@ pub const StandaloneModuleGraph = struct {

Global.exit(1);
};
_ = bun.sys.close(fd);

if (windows_icon) |icon_utf8| {
var icon_buf: bun.OSPathBuffer = undefined;
const icon = bun.strings.toWPathNormalized(&icon_buf, icon_utf8);
bun.windows.rescle.setIcon(outfile_slice, icon) catch {
Output.warn("Failed to set executable icon", .{});
};
}
return;
}

Expand Down
14 changes: 14 additions & 0 deletions src/bun.js/bindings/windows/rescle-binding.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "root.h"
#include "rescle.h"

extern "C" int rescle__setIcon(const WCHAR* exeFilename, const WCHAR* iconFilename)
{
rescle::ResourceUpdater updater;
if (!updater.Load(exeFilename))
return -1;
if (!updater.SetIcon(iconFilename))
return -2;
if (!updater.Commit())
return -3;
return 0;
}
Loading

0 comments on commit 7b3554f

Please sign in to comment.