mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
feat(bundler): add --windows-icon, --windows-no-console, fix bun.exe's main icon (#15894)
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com> Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com>
This commit is contained in:
@@ -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(
|
||||
@@ -650,11 +652,19 @@ 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 ---
|
||||
@@ -662,7 +672,7 @@ endif()
|
||||
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)
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)});
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
14
src/bun.js/bindings/windows/rescle-binding.cpp
Normal file
14
src/bun.js/bindings/windows/rescle-binding.cpp
Normal file
@@ -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;
|
||||
}
|
||||
1090
src/bun.js/bindings/windows/rescle.cpp
Normal file
1090
src/bun.js/bindings/windows/rescle.cpp
Normal file
File diff suppressed because it is too large
Load Diff
211
src/bun.js/bindings/windows/rescle.h
Normal file
211
src/bun.js/bindings/windows/rescle.h
Normal file
@@ -0,0 +1,211 @@
|
||||
// This file is from Electron's fork of rescle
|
||||
// https://github.com/electron/rcedit/blob/e36b688b42df0e236922019ce14e0ea165dc176d/src/rescle.h
|
||||
// 'bun build --compile' uses this on Windows to allow
|
||||
// patching the icon of the generated executable.
|
||||
//
|
||||
// Copyright (c) 2013 GitHub Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by MIT license that can be found in the
|
||||
// LICENSE file.
|
||||
//
|
||||
// This file is modified from Rescle written by yoshio.okumura@gmail.com:
|
||||
// http://code.google.com/p/rescle/
|
||||
|
||||
#ifndef VERSION_INFO_UPDATER
|
||||
#define VERSION_INFO_UPDATER
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <windows.h>
|
||||
#include <memory> // unique_ptr
|
||||
|
||||
#define RU_VS_COMMENTS L"Comments"
|
||||
#define RU_VS_COMPANY_NAME L"CompanyName"
|
||||
#define RU_VS_FILE_DESCRIPTION L"FileDescription"
|
||||
#define RU_VS_FILE_VERSION L"FileVersion"
|
||||
#define RU_VS_INTERNAL_NAME L"InternalName"
|
||||
#define RU_VS_LEGAL_COPYRIGHT L"LegalCopyright"
|
||||
#define RU_VS_LEGAL_TRADEMARKS L"LegalTrademarks"
|
||||
#define RU_VS_ORIGINAL_FILENAME L"OriginalFilename"
|
||||
#define RU_VS_PRIVATE_BUILD L"PrivateBuild"
|
||||
#define RU_VS_PRODUCT_NAME L"ProductName"
|
||||
#define RU_VS_PRODUCT_VERSION L"ProductVersion"
|
||||
#define RU_VS_SPECIAL_BUILD L"SpecialBuild"
|
||||
|
||||
namespace rescle {
|
||||
|
||||
struct IconsValue {
|
||||
typedef struct _ICONENTRY {
|
||||
BYTE width;
|
||||
BYTE height;
|
||||
BYTE colorCount;
|
||||
BYTE reserved;
|
||||
WORD planes;
|
||||
WORD bitCount;
|
||||
DWORD bytesInRes;
|
||||
DWORD imageOffset;
|
||||
} ICONENTRY;
|
||||
|
||||
typedef struct _ICONHEADER {
|
||||
WORD reserved;
|
||||
WORD type;
|
||||
WORD count;
|
||||
std::vector<ICONENTRY> entries;
|
||||
} ICONHEADER;
|
||||
|
||||
ICONHEADER header;
|
||||
std::vector<std::vector<BYTE>> images;
|
||||
std::vector<BYTE> grpHeader;
|
||||
};
|
||||
|
||||
struct Translate {
|
||||
LANGID wLanguage;
|
||||
WORD wCodePage;
|
||||
};
|
||||
|
||||
typedef std::pair<std::wstring, std::wstring> VersionString;
|
||||
typedef std::pair<const BYTE* const, const size_t> OffsetLengthPair;
|
||||
|
||||
struct VersionStringTable {
|
||||
Translate encoding;
|
||||
std::vector<VersionString> strings;
|
||||
};
|
||||
|
||||
class VersionInfo {
|
||||
public:
|
||||
VersionInfo();
|
||||
VersionInfo(HMODULE hModule, WORD languageId);
|
||||
|
||||
std::vector<BYTE> Serialize() const;
|
||||
|
||||
bool HasFixedFileInfo() const;
|
||||
VS_FIXEDFILEINFO& GetFixedFileInfo();
|
||||
const VS_FIXEDFILEINFO& GetFixedFileInfo() const;
|
||||
void SetFixedFileInfo(const VS_FIXEDFILEINFO& value);
|
||||
|
||||
std::vector<VersionStringTable> stringTables;
|
||||
std::vector<Translate> supportedTranslations;
|
||||
|
||||
private:
|
||||
VS_FIXEDFILEINFO fixedFileInfo_;
|
||||
|
||||
void FillDefaultData();
|
||||
void DeserializeVersionInfo(const BYTE* pData, size_t size);
|
||||
|
||||
VersionStringTable DeserializeVersionStringTable(const BYTE* tableData);
|
||||
void DeserializeVersionStringFileInfo(const BYTE* offset, size_t length, std::vector<VersionStringTable>& stringTables);
|
||||
void DeserializeVarFileInfo(const unsigned char* offset, std::vector<Translate>& translations);
|
||||
OffsetLengthPair GetChildrenData(const BYTE* entryData);
|
||||
};
|
||||
|
||||
class ResourceUpdater {
|
||||
public:
|
||||
typedef std::vector<std::wstring> StringValues;
|
||||
typedef std::map<UINT, StringValues> StringTable;
|
||||
typedef std::map<WORD, StringTable> StringTableMap;
|
||||
typedef std::map<LANGID, VersionInfo> VersionStampMap;
|
||||
typedef std::map<UINT, std::unique_ptr<IconsValue>> IconTable;
|
||||
typedef std::vector<BYTE> RcDataValue;
|
||||
typedef std::map<ptrdiff_t, RcDataValue> RcDataMap;
|
||||
typedef std::map<LANGID, RcDataMap> RcDataLangMap;
|
||||
|
||||
struct IconResInfo {
|
||||
UINT maxIconId = 0;
|
||||
IconTable iconBundles;
|
||||
};
|
||||
|
||||
typedef std::map<LANGID, IconResInfo> IconTableMap;
|
||||
|
||||
ResourceUpdater();
|
||||
~ResourceUpdater();
|
||||
|
||||
bool Load(const WCHAR* filename);
|
||||
bool SetVersionString(WORD languageId, const WCHAR* name, const WCHAR* value);
|
||||
bool SetVersionString(const WCHAR* name, const WCHAR* value);
|
||||
const WCHAR* GetVersionString(WORD languageId, const WCHAR* name);
|
||||
const WCHAR* GetVersionString(const WCHAR* name);
|
||||
bool SetProductVersion(WORD languageId, UINT id, unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4);
|
||||
bool SetProductVersion(unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4);
|
||||
bool SetFileVersion(WORD languageId, UINT id, unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4);
|
||||
bool SetFileVersion(unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4);
|
||||
bool ChangeString(WORD languageId, UINT id, const WCHAR* value);
|
||||
bool ChangeString(UINT id, const WCHAR* value);
|
||||
bool ChangeRcData(UINT id, const WCHAR* pathToResource);
|
||||
const WCHAR* GetString(WORD languageId, UINT id);
|
||||
const WCHAR* GetString(UINT id);
|
||||
bool SetIcon(const WCHAR* path, const LANGID& langId, UINT iconBundle);
|
||||
bool SetIcon(const WCHAR* path, const LANGID& langId);
|
||||
bool SetIcon(const WCHAR* path);
|
||||
bool SetExecutionLevel(const WCHAR* value);
|
||||
bool IsExecutionLevelSet();
|
||||
bool SetApplicationManifest(const WCHAR* value);
|
||||
bool IsApplicationManifestSet();
|
||||
bool Commit();
|
||||
|
||||
private:
|
||||
bool SerializeStringTable(const StringValues& values, UINT blockId, std::vector<char>* out);
|
||||
|
||||
static BOOL CALLBACK OnEnumResourceName(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam);
|
||||
static BOOL CALLBACK OnEnumResourceManifest(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam);
|
||||
static BOOL CALLBACK OnEnumResourceLanguage(HANDLE hModule, LPCWSTR lpszType, LPCWSTR lpszName, WORD wIDLanguage, LONG_PTR lParam);
|
||||
|
||||
HMODULE module_;
|
||||
std::wstring filename_;
|
||||
std::wstring executionLevel_;
|
||||
std::wstring originalExecutionLevel_;
|
||||
std::wstring applicationManifestPath_;
|
||||
std::wstring manifestString_;
|
||||
VersionStampMap versionStampMap_;
|
||||
StringTableMap stringTableMap_;
|
||||
IconTableMap iconBundleMap_;
|
||||
RcDataLangMap rcDataLngMap_;
|
||||
};
|
||||
|
||||
class ScopedResourceUpdater {
|
||||
public:
|
||||
ScopedResourceUpdater(const WCHAR* filename, bool deleteOld);
|
||||
~ScopedResourceUpdater();
|
||||
|
||||
HANDLE Get() const;
|
||||
bool Commit();
|
||||
|
||||
private:
|
||||
bool EndUpdate(bool doesCommit);
|
||||
|
||||
HANDLE handle_;
|
||||
bool commited_ = false;
|
||||
};
|
||||
|
||||
} // namespace rescle
|
||||
|
||||
#endif // VERSION_INFO_UPDATER
|
||||
38
src/cli.zig
38
src/cli.zig
@@ -290,7 +290,9 @@ pub const Arguments = struct {
|
||||
clap.parseParam("--conditions <STR>... Pass custom conditions to resolve") catch unreachable,
|
||||
clap.parseParam("--app (EXPERIMENTAL) Build a web app for production using Bun Bake.") catch unreachable,
|
||||
clap.parseParam("--server-components (EXPERIMENTAL) Enable server components") catch unreachable,
|
||||
clap.parseParam("--env <inline|prefix*|disable> Inline environment variables into the bundle as process.env.${name}. Defaults to 'inline'. To inline environment variables matching a prefix, use my prefix like 'FOO_PUBLIC_*'. To disable, use 'disable'. In Bun v1.2+, the default is 'disable'.") catch unreachable,
|
||||
clap.parseParam("--env <inline|prefix*|disable> Inline environment variables into the bundle as process.env.${name}. Defaults to 'inline'. To inline environment variables matching a prefix, use my prefix like 'FOO_PUBLIC_*'. To disable, use 'disable'. In Bun v1.2+, the default is 'disable'.") catch unreachable,
|
||||
clap.parseParam("--windows-hide-console When using --compile targeting Windows, prevent a Command prompt from opening alongside the executable") catch unreachable,
|
||||
clap.parseParam("--windows-icon <STR> When using --compile targeting Windows, assign an executable icon") catch unreachable,
|
||||
} ++ if (FeatureFlags.bake_debugging_features) [_]ParamType{
|
||||
clap.parseParam("--debug-dump-server-files When --app is set, dump all server files to disk even when building statically") catch unreachable,
|
||||
clap.parseParam("--debug-no-minify When --app is set, do not minify anything") catch unreachable,
|
||||
@@ -928,6 +930,31 @@ pub const Arguments = struct {
|
||||
ctx.bundler_options.inline_entrypoint_import_meta_main = true;
|
||||
}
|
||||
|
||||
if (args.flag("--windows-hide-console")) {
|
||||
// --windows-hide-console technically doesnt depend on WinAPI, but since since --windows-icon
|
||||
// does, all of these customization options have been gated to windows-only
|
||||
if (!Environment.isWindows) {
|
||||
Output.errGeneric("Using --windows-hide-console is only available when compiling on Windows", .{});
|
||||
Global.crash();
|
||||
}
|
||||
if (!ctx.bundler_options.compile) {
|
||||
Output.errGeneric("--windows-hide-console requires --compile", .{});
|
||||
Global.crash();
|
||||
}
|
||||
ctx.bundler_options.windows_hide_console = true;
|
||||
}
|
||||
if (args.option("--windows-icon")) |path| {
|
||||
if (!Environment.isWindows) {
|
||||
Output.errGeneric("Using --windows-icon is only available when compiling on Windows", .{});
|
||||
Global.crash();
|
||||
}
|
||||
if (!ctx.bundler_options.compile) {
|
||||
Output.errGeneric("--windows-icon requires --compile", .{});
|
||||
Global.crash();
|
||||
}
|
||||
ctx.bundler_options.windows_icon = path;
|
||||
}
|
||||
|
||||
if (args.option("--outdir")) |outdir| {
|
||||
if (outdir.len > 0) {
|
||||
ctx.bundler_options.outdir = outdir;
|
||||
@@ -1456,9 +1483,6 @@ pub const Command = struct {
|
||||
has_loaded_global_config: bool = false,
|
||||
|
||||
pub const BundlerOptions = struct {
|
||||
compile: bool = false,
|
||||
compile_target: Cli.CompileTarget = .{},
|
||||
|
||||
outdir: []const u8 = "",
|
||||
outfile: []const u8 = "",
|
||||
root_dir: []const u8 = "",
|
||||
@@ -1489,6 +1513,12 @@ pub const Command = struct {
|
||||
|
||||
env_behavior: Api.DotEnvBehavior = .disable,
|
||||
env_prefix: []const u8 = "",
|
||||
|
||||
// Compile options
|
||||
compile: bool = false,
|
||||
compile_target: Cli.CompileTarget = .{},
|
||||
windows_hide_console: bool = false,
|
||||
windows_icon: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, log: *logger.Log, comptime command: Command.Tag) anyerror!Context {
|
||||
|
||||
@@ -418,6 +418,8 @@ pub const BuildCommand = struct {
|
||||
outfile,
|
||||
this_bundler.env,
|
||||
this_bundler.options.output_format,
|
||||
ctx.bundler_options.windows_hide_console,
|
||||
ctx.bundler_options.windows_icon,
|
||||
);
|
||||
const compiled_elapsed = @divTrunc(@as(i64, @truncate(std.time.nanoTimestamp() - bundled_end)), @as(i64, std.time.ns_per_ms));
|
||||
const compiled_elapsed_digit_count: isize = switch (compiled_elapsed) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "windows.h"
|
||||
|
||||
IDI_MYICON ICON "@BUN_ICO_PATH@"
|
||||
IDI_MYICON ICON "bun.ico"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @Bun_VERSION_MAJOR@,@Bun_VERSION_MINOR@,@Bun_VERSION_PATCH@,0
|
||||
|
||||
@@ -3627,3 +3627,33 @@ pub const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000;
|
||||
pub const JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x400;
|
||||
pub const JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x800;
|
||||
pub const JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000;
|
||||
|
||||
const pe_header_offset_location = 0x3C;
|
||||
const subsystem_offset = 0x5C;
|
||||
|
||||
pub const Subsystem = enum(u16) {
|
||||
windows_gui = 2,
|
||||
};
|
||||
|
||||
pub fn editWin32BinarySubsystem(fd: bun.sys.File, subsystem: Subsystem) !void {
|
||||
comptime bun.assert(bun.Environment.isWindows);
|
||||
if (bun.windows.SetFilePointerEx(fd.handle.cast(), pe_header_offset_location, null, std.os.windows.FILE_BEGIN) == 0)
|
||||
return error.Win32Error;
|
||||
const offset = try fd.reader().readInt(u32, .little);
|
||||
if (bun.windows.SetFilePointerEx(fd.handle.cast(), offset + subsystem_offset, null, std.os.windows.FILE_BEGIN) == 0)
|
||||
return error.Win32Error;
|
||||
try fd.writer().writeInt(u16, @intFromEnum(subsystem), .little);
|
||||
}
|
||||
|
||||
pub const rescle = struct {
|
||||
extern fn rescle__setIcon([*:0]const u16, [*:0]const u16) c_int;
|
||||
|
||||
pub fn setIcon(exe_path: [*:0]const u16, icon: [*:0]const u16) !void {
|
||||
comptime bun.assert(bun.Environment.isWindows);
|
||||
const status = rescle__setIcon(exe_path, icon);
|
||||
return switch (status) {
|
||||
0 => {},
|
||||
else => error.IconEditError,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user