cmake_minimum_required(VERSION 3.22) cmake_policy(SET CMP0091 NEW) cmake_policy(SET CMP0067 NEW) set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) set(Bun_VERSION "1.1.24") set(WEBKIT_TAG 1cdc5e606ad7d451853f75a068a320148385f397) set(BUN_WORKDIR "${CMAKE_CURRENT_BINARY_DIR}") message(STATUS "Configuring Bun ${Bun_VERSION} in ${BUN_WORKDIR}") set(CMAKE_COLOR_DIAGNOSTICS ON) set(CMAKE_CXX_STANDARD 20) set(CMAKE_C_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON) option(ZIG_CACHE_DIR "Path to the Zig cache directory" "") if(NOT ZIG_CACHE_DIR) SET(ZIG_CACHE_DIR "${BUN_WORKDIR}") cmake_path(APPEND ZIG_CACHE_DIR "zig-cache") endif() set(LOCAL_ZIG_CACHE_DIR "${ZIG_CACHE_DIR}") set(GLOBAL_ZIG_CACHE_DIR "${ZIG_CACHE_DIR}") cmake_path(APPEND LOCAL_ZIG_CACHE_DIR "local") cmake_path(APPEND GLOBAL_ZIG_CACHE_DIR "global") # Used in process.version, process.versions.node, napi, and elsewhere set(REPORTED_NODEJS_VERSION "22.6.0") # Used in process.versions.modules and compared while loading V8 modules set(REPORTED_NODEJS_ABI_VERSION "127") # WebKit uses -std=gnu++20 on non-macOS non-Windows # If we do not set this, it will crash at startup on the first memory allocation. if(NOT WIN32 AND NOT APPLE) set(CMAKE_CXX_EXTENSIONS ON) set(CMAKE_POSITION_INDEPENDENT_CODE FALSE) endif() # --- Build Type --- if(NOT CMAKE_BUILD_TYPE) message(WARNING "No CMAKE_BUILD_TYPE value specified, defaulting to Debug.\nSet a build type with -DCMAKE_BUILD_TYPE=") set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build (Debug, Release)" FORCE) else() if(NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|Release)$") message(FATAL_ERROR "Invalid CMAKE_BUILD_TYPE value specified: ${CMAKE_BUILD_TYPE}\n" "CMAKE_BUILD_TYPE must be Debug or Release.") endif() message(STATUS "The CMake build type is: ${CMAKE_BUILD_TYPE}") endif() if(WIN32 AND NOT CMAKE_CL_SHOWINCLUDES_PREFIX) # workaround until cmake fix is shipped https://github.com/ninja-build/ninja/issues/2280 # './build/.ninja_deps' may need to be deleted, the bug is "Note: including file: ..." is saved # as part of some file paths set(CMAKE_CL_SHOWINCLUDES_PREFIX "Note: including file:") endif() if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(DEBUG ON) set(DEFAULT_ZIG_OPTIMIZE "Debug") set(bun "bun-debug") # COMPILE_COMMANDS set(CMAKE_EXPORT_COMPILE_COMMANDS ON) elseif(CMAKE_BUILD_TYPE STREQUAL "Release") set(DEBUG OFF) set(DEFAULT_ZIG_OPTIMIZE "ReleaseFast") if(WIN32) # Debug symbols are in a separate file: bun.pdb set(bun "bun") set(DEFAULT_ZIG_OPTIMIZE "ReleaseSafe") else() if(ZIG_OPTIMIZE STREQUAL "Debug") set(bun "bun-debug") else() set(bun "bun-profile") endif() endif() endif() # --- MacOS SDK --- if(APPLE AND DEFINED ENV{CI}) set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0") endif() if(APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET) execute_process(COMMAND xcrun --show-sdk-path OUTPUT_VARIABLE SDKROOT) string(STRIP ${SDKROOT} SDKROOT) message(STATUS "MacOS SDK path: ${SDKROOT}") SET(CMAKE_OSX_SYSROOT ${SDKROOT}) execute_process(COMMAND xcrun --sdk macosx --show-sdk-version OUTPUT_VARIABLE MACOSX_DEPLOYMENT_TARGET) string(STRIP ${MACOSX_DEPLOYMENT_TARGET} MACOSX_DEPLOYMENT_TARGET) set(CMAKE_OSX_DEPLOYMENT_TARGET ${MACOSX_DEPLOYMENT_TARGET}) # Check if current version of macOS is less than the deployment target and if so, raise an error execute_process(COMMAND sw_vers -productVersion OUTPUT_VARIABLE MACOS_VERSION) string(STRIP ${MACOS_VERSION} MACOS_VERSION) if(MACOS_VERSION VERSION_LESS ${MACOSX_DEPLOYMENT_TARGET}) message(WARNING "The current version of macOS (${MACOS_VERSION}) is less than the deployment target (${MACOSX_DEPLOYMENT_TARGET}).\n" "The build will be incompatible with your current device due to mismatches in `icucore` versions.\n" "To fix this, please either:\n" " - Upgrade to at least macOS ${MACOSX_DEPLOYMENT_TARGET}\n" " - Use `xcode-select` to switch to an SDK version <= ${MACOS_VERSION}\n" " - Set CMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_VERSION} (make sure to build all dependencies with this variable set too)" ) endif() endif() if(APPLE) message(STATUS "Building for macOS v${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() # --- LLVM --- # This detection is a little overkill, but it ensures that the set LLVM_VERSION matches under # any case possible. Sorry for the complexity... # # Bun and WebKit must be compiled with the same compiler, so we do as much as we can to ensure that # the compiler used for the prebuilt WebKit is the same as we install as a dependency. # # It has to be done before project() is called, so that CMake doesnt pick a compiler for us, but even then # we do some extra work afterwards to double-check, and we will rerun BUN_FIND_LLVM if the compiler did not match. # # If the user passes -DLLVM_PREFIX, most of this logic is skipped, but we still warn if invalid. if(WIN32 OR APPLE) set(LLVM_VERSION 18) else() set(LLVM_VERSION 16) endif() macro(BUN_FIND_LLVM) find_program( _LLVM_CXX_PATH NAMES clang++-${LLVM_VERSION} clang++ PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to LLVM ${LLVM_VERSION}'s clang++ binary. Please pass -DLLVM_PREFIX with the path to LLVM" ) if(NOT _LLVM_CXX_PATH) message(FATAL_ERROR "Could not find LLVM ${LLVM_VERSION}, search paths: ${PLATFORM_LLVM_SEARCH_PATHS}") endif() set(CMAKE_CXX_COMPILER "${_LLVM_CXX_PATH}") find_program( _LLVM_C_PATH NAMES clang-${LLVM_VERSION} clang PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to LLVM ${LLVM_VERSION}'s clang binary. Please pass -DLLVM_PREFIX with the path to LLVM" ) if(NOT _LLVM_C_PATH) message(FATAL_ERROR "Could not find LLVM ${LLVM_VERSION}, search paths: ${PLATFORM_LLVM_SEARCH_PATHS}") endif() set(CMAKE_C_COMPILER "${_LLVM_C_PATH}") find_program( STRIP NAMES llvm-strip PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to LLVM ${LLVM_VERSION}'s llvm-strip binary" ) find_program( STRIP NAMES strip PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to strip binary" ) find_program( DSYMUTIL NAMES dsymutil PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to LLVM ${LLVM_VERSION}'s dsymutil binary" ) find_program( AR NAMES llvm-ar PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to LLVM ${LLVM_VERSION}'s llvm-ar binary" ) find_program( AR NAMES ar PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to LLVM ${LLVM_VERSION}'s llvm-ar binary" ) find_program( RANLIB NAMES llvm-ranlib PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to LLVM ${LLVM_VERSION}'s llvm-ar binary" ) execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE _tmp) string(REGEX MATCH "version ([0-9]+)\\.([0-9]+)\\.([0-9]+)" CMAKE_CXX_COMPILER_VERSION "${_tmp}") set(CMAKE_CXX_COMPILER_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") endmacro() if(UNIX) if(LLVM_PREFIX) set(PLATFORM_LLVM_SEARCH_PATHS ${LLVM_PREFIX}/bin) else() set(PLATFORM_LLVM_SEARCH_PATHS /usr/lib/llvm-${LLVM_VERSION}/bin /usr/lib/llvm${LLVM_VERSION}/bin /usr/bin /usr/local/bin) if(APPLE) set(PLATFORM_LLVM_SEARCH_PATHS /opt/homebrew/opt/llvm@${LLVM_VERSION}/bin /opt/homebrew/bin ${PLATFORM_LLVM_SEARCH_PATHS}) endif() endif() if(CMAKE_CXX_COMPILER) set(_LLVM_CXX_PATH "${CMAKE_CXX_COMPILER}") endif() if(CMAKE_C_COMPILER) set(_LLVM_C_PATH "${CMAKE_C_COMPILER}") endif() BUN_FIND_LLVM() else() # Windows uses Clang-CL # TODO: good configuration in this regard. -G Ninja will pick clang-cl if possible, which should be fine for most users. if(NOT CMAKE_C_COMPILER) set(CMAKE_C_COMPILER "clang-cl") endif() if(NOT CMAKE_CXX_COMPILER) set(CMAKE_CXX_COMPILER "clang-cl") endif() find_program( STRIP NAMES llvm-strip PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to LLVM ${LLVM_VERSION}'s llvm-strip binary" ) find_program( AR NAMES llvm-ar PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS} DOC "Path to LLVM ${LLVM_VERSION}'s llvm-ar binary" ) endif() project(Bun VERSION "${Bun_VERSION}") # if(MSVC) # message(FATAL_ERROR "Bun does not support building with MSVC. Please use `cmake -G Ninja` with LLVM ${LLVM_VERSION} and Ninja.") # endif() # More effort to prevent using the wrong C++ compiler if(UNIX) if((NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR(NOT CMAKE_CXX_COMPILER_VERSION MATCHES "^${LLVM_VERSION}\.")) # Attempt to auto-correct the compiler message(STATUS "Compiler mismatch, attempting to auto-correct") unset(_LLVM_CXX_PATH) BUN_FIND_LLVM() if((NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR(NOT CMAKE_CXX_COMPILER_VERSION MATCHES "^${LLVM_VERSION}\.")) message(WARNING "Expected LLVM ${LLVM_VERSION} as the C++ compiler, build may fail or break at runtime.") endif() endif() endif() message(STATUS "C++ Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} at ${CMAKE_CXX_COMPILER}") # --- End LLVM --- if(NOT WIN32) set(SHELL "bash") set(SCRIPT_EXTENSION "sh") else() set(SCRIPT_EXTENSION "ps1") # pwsh is the new powershell, powershell is the old one. find_program(SHELL NAMES pwsh powershell) endif() set(DEFAULT_ON_UNLESS_APPLE ON) if(APPLE) set(DEFAULT_ON_UNLESS_APPLE OFF) endif() set(CI OFF) if(DEFINED ENV{CI} OR DEFINED ENV{GITHUB_ACTIONS}) set(CI ON) endif() set(DEFAULT_USE_STATIC_LIBATOMIC ON) set(DEFAULT_USE_DEBUG_JSC, OFF) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(DEFAULT_USE_DEBUG_JSC ON) set(DEFAULT_LTO OFF) elseif(CMAKE_BUILD_TYPE STREQUAL "Release") if(CI) set(DEFAULT_LTO ON) else() set(DEFAULT_LTO OFF) endif() endif() if(WIN32) set(DEFAULT_USE_DEBUG_JSC OFF) endif() if(UNIX AND NOT APPLE) execute_process(COMMAND grep -w "NAME" /etc/os-release OUTPUT_VARIABLE LINUX_DISTRO) if(${LINUX_DISTRO} MATCHES "NAME=\"(Arch|Manjaro|Artix) Linux\"|NAME=\"openSUSE Tumbleweed\"\n") set(DEFAULT_USE_STATIC_LIBATOMIC OFF) endif() endif() # -- Build Flags -- option(USE_STATIC_SQLITE "Statically link SQLite?" ${DEFAULT_ON_UNLESS_APPLE}) option(USE_CUSTOM_ZLIB "Use Bun's recommended version of zlib" ON) option(USE_CUSTOM_LIBDEFLATE "Use Bun's recommended version of libdeflate" ON) option(USE_CUSTOM_BORINGSSL "Use Bun's recommended version of BoringSSL" ON) option(USE_CUSTOM_LIBARCHIVE "Use Bun's recommended version of libarchive" ON) option(USE_CUSTOM_MIMALLOC "Use Bun's recommended version of Mimalloc" ON) option(USE_CUSTOM_ZSTD "Use Bun's recommended version of zstd" ON) option(USE_CUSTOM_CARES "Use Bun's recommended version of c-ares" ON) option(USE_CUSTOM_LOLHTML "Use Bun's recommended version of lolhtml" ON) option(USE_CUSTOM_TINYCC "Use Bun's recommended version of tinycc" ON) option(USE_CUSTOM_LIBUV "Use Bun's recommended version of libuv (Windows only)" ON) option(USE_CUSTOM_LSHPACK "Use Bun's recommended version of ls-hpack" ON) option(USE_BASELINE_BUILD "Build Bun for baseline (older) CPUs" OFF) option(USE_SYSTEM_ICU "Use the system-provided libicu. May fix startup crashes when building WebKit yourself." OFF) option(USE_VALGRIND "Build Bun with Valgrind support (Linux only)" OFF) option(ZIG_OPTIMIZE "Optimization level for Zig" ${DEFAULT_ZIG_OPTIMIZE}) option(USE_DEBUG_JSC "Enable assertions and use a debug build of JavaScriptCore" ${DEFAULT_USE_DEBUG_JSC}) option(USE_UNIFIED_SOURCES "Use unified sources to speed up the build" OFF) option(USE_STATIC_LIBATOMIC "Statically link libatomic, requires the presence of libatomic.a" ${DEFAULT_USE_STATIC_LIBATOMIC}) option(USE_LTO "Enable Link-Time Optimization" ${DEFAULT_LTO}) if(APPLE AND USE_LTO) set(USE_LTO OFF) message(FATAL_ERROR "Link-Time Optimization is not supported on macOS because it requires -fuse-ld=lld and lld causes many segfaults on macOS (likely related to stack size)") endif() if(WIN32 AND USE_LTO) set(CMAKE_LINKER_TYPE LLD) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) endif() option(BUN_TIDY_ONLY "Only run clang-tidy" OFF) option(BUN_TIDY_ONLY_EXTRA " Only run clang-tidy, with extra checks for local development" OFF) if(NOT ZIG_LIB_DIR) cmake_path(SET ZIG_LIB_DIR NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/src/deps/zig/lib") endif() if(USE_VALGRIND) # Disable SIMD set(USE_BASELINE_BUILD ON) if(ARCH STREQUAL "x86_64") # This is for picohttpparser # Valgrind cannot handle SSE4.2 instructions add_compile_definitions("__SSE4_2__=0") endif() endif() if(NOT CANARY) set(CANARY 0) endif() if(NOT ENABLE_LOGS) set(ENABLE_LOGS false) endif() if(NOT ZIG_OPTIMIZE) set(ZIG_OPTIMIZE ${DEFAULT_ZIG_OPTIMIZE}) endif() set(ERROR_LIMIT 100 CACHE STRING "Maximum number of errors to show when compiling C++ code") set(ARCH x86_64) set(HOMEBREW_PREFIX "/usr/local") if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|arm") set(ARCH aarch64) set(HOMEBREW_PREFIX "/opt/homebrew") endif() if(NOT CPU_TARGET) if(DEFINED ENV{CPU_TARGET}) set(CPU_TARGET $ENV{CPU_TARGET}) else() set(CPU_TARGET "native" CACHE STRING "CPU target for the compiler" FORCE) if(ARCH STREQUAL "x86_64") if(USE_BASELINE_BUILD) set(CPU_TARGET "nehalem") else() set(CPU_TARGET "haswell") endif() endif() endif() endif() message(STATUS "Building for CPU Target: ${CPU_TARGET}") if(NOT ZIG_TARGET) set(ZIG_TARGET "native") if(WIN32) set(ZIG_TARGET "${ARCH}-windows-msvc") endif() endif() set(CONFIGURE_DEPENDS "CONFIGURE_DEPENDS") if(NO_CONFIGURE_DEPENDS) set(CONFIGURE_DEPENDS "") endif() # --- CLI Paths --- set(REQUIRED_IF_NOT_ONLY_CPP_OR_LINK "") if(NOT BUN_CPP_ONLY AND NOT BUN_LINK_ONLY) set(REQUIRED_IF_NOT_ONLY_CPP_OR_LINK "REQUIRED") endif() # Zig Compiler function(validate_zig validator_result_var item) set(${validator_result_var} FALSE PARENT_SCOPE) # We will allow any valid zig compiler, as long as it contains some text from `zig zen` # Ideally we would do a version or feature check, but that would be quite slow execute_process(COMMAND ${item} zen OUTPUT_VARIABLE ZIG_ZEN_OUTPUT) if(ZIG_ZEN_OUTPUT MATCHES "Together we serve the users") set(${validator_result_var} TRUE PARENT_SCOPE) else() set(${validator_result_var} FALSE PARENT_SCOPE) endif() endfunction() if(ZIG_COMPILER) if(ZIG_COMPILER STREQUAL "system") message(STATUS "Using system Zig compiler") unset(ZIG_COMPILER_) endif() find_program(ZIG_COMPILER_ zig ${REQUIRED_IF_NOT_ONLY_CPP_OR_LINK} DOC "Path to the Zig compiler" VALIDATOR validate_zig) set(ZIG_COMPILER "${ZIG_COMPILER_}") message(STATUS "Found Zig Compiler: ${ZIG_COMPILER}") elseif(NOT BUN_CPP_ONLY AND NOT BUN_LINK_ONLY AND NOT BUN_TIDY_ONLY AND NOT BUN_TIDY_ONLY_EXTRA) execute_process( COMMAND "${SHELL}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/download-zig.${SCRIPT_EXTENSION}" ) set(ZIG_COMPILER "${CMAKE_CURRENT_SOURCE_DIR}/.cache/zig/zig") if(WIN32) set(ZIG_COMPILER "${ZIG_COMPILER}.exe") endif() if(NOT EXISTS "${ZIG_COMPILER}") unset(ZIG_COMPILER) message(FATAL_ERROR "Auto-installation of Zig failed. Please pass -DZIG_COMPILER=system or a path to the Zig") endif() message(STATUS "Installed Zig Compiler: ${ZIG_COMPILER}") set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "build.zig") message(STATUS "Using zig cache directory: ${ZIG_CACHE_DIR}") endif() # Bun find_program(BUN_EXECUTABLE bun ${REQUIRED_IF_NOT_ONLY_CPP_OR_LINK} DOC "Path to an already built release of Bun") message(STATUS "Found Bun: ${BUN_EXECUTABLE}") if(WIN32 AND NO_CODEGEN) # TODO(@paperdave): remove this, see bun-windows.yml's comment. set(BUN_EXECUTABLE "echo") endif() # Prettier find_program(PRETTIER prettier DOC "Path to prettier" PATHS ./node_modules/.bin ENV PATH) # Esbuild (TODO: switch these to "bun build") find_program(ESBUILD esbuild DOC "Path to esbuild" PATHS ./node_modules/.bin ENV PATH) # Ruby (only needed for unified sources) if(USE_UNIFIED_SOURCES) # ruby 'WebKit/Source/WTF/Scripts/generate-unified-source-bundles.rb' source_list.txt --source-tree-path . --derived-sources-path build/unified-sources find_program(RUBY ruby DOC "Path to ruby") endif() # CCache # find_program(CCACHE_PROGRAM sccache) find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") message(STATUS "Using ccache: ${CCACHE_PROGRAM}") endif() # --- WebKit --- # WebKit is either prebuilt and distributed via NPM, or you can pass WEBKIT_DIR to use a local build. # We cannot include their CMake build files (TODO: explain why, for now ask @paperdave why) # # On Unix, this will pull from NPM the single package that is needed and use that if(WIN32) set(STATIC_LIB_EXT "lib") set(libJavaScriptCore "JavaScriptCore") set(libWTF "WTF") else() set(STATIC_LIB_EXT "a") set(libJavaScriptCore "libJavaScriptCore") set(libWTF "libWTF") endif() if(NOT WEBKIT_DIR) set(BUN_WEBKIT_PACKAGE_NAME_SUFFIX "") set(ASSERT_ENABLED "0") if(USE_DEBUG_JSC) add_compile_definitions("BUN_DEBUG=1") set(BUN_WEBKIT_PACKAGE_NAME_SUFFIX "-debug") set(ASSERT_ENABLED "1") elseif(NOT DEBUG AND NOT WIN32) # Avoid waiting for LTO in local release builds outside of CI if(USE_LTO) set(BUN_WEBKIT_PACKAGE_NAME_SUFFIX "-lto") else() set(BUN_WEBKIT_PACKAGE_NAME_SUFFIX "") endif() set(ASSERT_ENABLED "0") endif() if(WIN32) set(BUN_WEBKIT_PACKAGE_PLATFORM "windows") elseif(APPLE) set(BUN_WEBKIT_PACKAGE_PLATFORM "macos") else() set(BUN_WEBKIT_PACKAGE_PLATFORM "linux") endif() if(ARCH STREQUAL "x86_64") set(BUN_WEBKIT_PACKAGE_ARCH "amd64") elseif(ARCH MATCHES "aarch64|arm64|arm") set(BUN_WEBKIT_PACKAGE_ARCH "arm64") endif() set(BUN_WEBKIT_PACKAGE_NAME "bun-webkit-${BUN_WEBKIT_PACKAGE_PLATFORM}-${BUN_WEBKIT_PACKAGE_ARCH}${BUN_WEBKIT_PACKAGE_NAME_SUFFIX}") message(STATUS "Using Pre-built WebKit: ${BUN_WEBKIT_PACKAGE_NAME}") execute_process( COMMAND "${SHELL}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/download-webkit.${SCRIPT_EXTENSION}" "${BUN_WORKDIR}/bun-webkit" "${WEBKIT_TAG}" "${BUN_WEBKIT_PACKAGE_NAME}" WORKING_DIRECTORY ${BUN_WORKDIR} ) if(NOT EXISTS "${BUN_WORKDIR}/bun-webkit") message(FATAL_ERROR "Prebuilt WebKit package ${BUN_WEBKIT_PACKAGE_NAME} failed to install") endif() set(WEBKIT_INCLUDE_DIR "${BUN_WORKDIR}/bun-webkit/include") if(APPLE) set(ICU_INCLUDE_DIR "") else() set(ICU_INCLUDE_DIR "${BUN_WORKDIR}/bun-webkit/include/wtf/unicode") endif() set(WEBKIT_LIB_DIR "${BUN_WORKDIR}/bun-webkit/lib") elseif(WEBKIT_DIR STREQUAL "omit") message(STATUS "Not using WebKit. This is only valid if you are only trying to build Zig code") else() # Expected to be WebKit/WebKitBuild/${CMAKE_BUILD_TYPE} if(EXISTS "${WEBKIT_DIR}/cmakeconfig.h") # You may need to run: # make jsc-compile-debug jsc-copy-headers include_directories( "${WEBKIT_DIR}/" "${WEBKIT_DIR}/JavaScriptCore/Headers/JavaScriptCore" "${WEBKIT_DIR}/JavaScriptCore/PrivateHeaders" "${WEBKIT_DIR}/bmalloc/Headers" "${WEBKIT_DIR}/WTF/Headers" ) set(WEBKIT_LIB_DIR "${WEBKIT_DIR}/lib") if(USE_DEBUG_JSC) add_compile_definitions("BUN_DEBUG=1") set(ASSERT_ENABLED "1") endif() message(STATUS "Using WebKit from ${WEBKIT_DIR}") else() if(NOT EXISTS "${WEBKIT_DIR}/lib/${libWTF}.${STATIC_LIB_EXT}" OR NOT EXISTS "${WEBKIT_DIR}/lib/${libJavaScriptCore}.${STATIC_LIB_EXT}") if(WEBKIT_DIR MATCHES "src/bun.js/WebKit$") message(FATAL_ERROR "WebKit directory ${WEBKIT_DIR} does not contain all the required files for Bun. Did you forget to init submodules?") endif() message(FATAL_ERROR "WebKit directory ${WEBKIT_DIR} does not contain all the required files for Bun. Expected a path to the oven-sh/WebKit repository, or a path to a folder containing `include` and `lib`.") endif() set(WEBKIT_INCLUDE_DIR "${WEBKIT_DIR}/include") set(WEBKIT_LIB_DIR "${WEBKIT_DIR}/lib") message(STATUS "Using specified WebKit directory: ${WEBKIT_DIR}") set(ASSERT_ENABLED "0") message(STATUS "WebKit assertions: OFF") endif() endif() # --- CMake Macros --- # Append the given dependencies to the source file macro(WEBKIT_ADD_SOURCE_DEPENDENCIES _source _deps) set(_tmp) get_source_file_property(_tmp ${_source} OBJECT_DEPENDS) if(NOT _tmp) set(_tmp "") endif() foreach(f ${_deps}) list(APPEND _tmp "${f}") endforeach() set_source_files_properties(${_source} PROPERTIES OBJECT_DEPENDS "${_tmp}") unset(_tmp) endmacro() # --- BUILD --- set(BUN_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src") set(BUN_DEPS_DIR "${BUN_SRC}/deps") set(BUN_CODEGEN_SRC "${BUN_SRC}/codegen") if(NOT BUN_DEPS_OUT_DIR) set(BUN_DEPS_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build/bun-deps") endif() set(BUN_RAW_SOURCES, "") file(GLOB BUN_CPP ${CONFIGURE_DEPENDS} "${BUN_SRC}/deps/*.cpp" "${BUN_SRC}/io/*.cpp" "${BUN_SRC}/bun.js/modules/*.cpp" "${BUN_SRC}/bun.js/bindings/*.cpp" "${BUN_SRC}/bun.js/bindings/webcore/*.cpp" "${BUN_SRC}/bun.js/bindings/sqlite/*.cpp" "${BUN_SRC}/bun.js/bindings/webcrypto/*.cpp" "${BUN_SRC}/bun.js/bindings/webcrypto/*/*.cpp" "${BUN_SRC}/bun.js/bindings/v8/*.cpp" "${BUN_SRC}/deps/picohttpparser/picohttpparser.c" ) list(APPEND BUN_RAW_SOURCES ${BUN_CPP}) # -- uSockets -- set(USOCKETS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/packages/bun-usockets/src") file(GLOB USOCKETS_FILES ${CONFIGURE_DEPENDS} "${USOCKETS_SRC}/*.c" "${USOCKETS_SRC}/eventing/*.c" "${USOCKETS_SRC}/internal/*.c" "${USOCKETS_SRC}/crypto/*.c" "${USOCKETS_SRC}/crypto/*.cpp" ) list(APPEND BUN_RAW_SOURCES ${USOCKETS_FILES}) # --- Classes Generator --- file(GLOB BUN_CLASSES_TS ${CONFIGURE_DEPENDS} "${BUN_SRC}/bun.js/*.classes.ts" "${BUN_SRC}/bun.js/api/*.classes.ts" "${BUN_SRC}/bun.js/test/*.classes.ts" "${BUN_SRC}/bun.js/webcore/*.classes.ts" "${BUN_SRC}/bun.js/node/*.classes.ts" ) add_custom_command( OUTPUT "${BUN_WORKDIR}/codegen/ZigGeneratedClasses.h" "${BUN_WORKDIR}/codegen/ZigGeneratedClasses.cpp" "${BUN_WORKDIR}/codegen/ZigGeneratedClasses+lazyStructureHeader.h" "${BUN_WORKDIR}/codegen/ZigGeneratedClasses+DOMClientIsoSubspaces.h" "${BUN_WORKDIR}/codegen/ZigGeneratedClasses+DOMIsoSubspaces.h" "${BUN_WORKDIR}/codegen/ZigGeneratedClasses+lazyStructureImpl.h" "${BUN_WORKDIR}/codegen/ZigGeneratedClasses.zig" COMMAND ${BUN_EXECUTABLE} run "${BUN_CODEGEN_SRC}/generate-classes.ts" ${BUN_CLASSES_TS} "${BUN_WORKDIR}/codegen" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} MAIN_DEPENDENCY "${BUN_CODEGEN_SRC}/generate-classes.ts" DEPENDS ${BUN_CLASSES_TS} VERBATIM COMMENT "Generating *.classes.ts bindings" ) list(APPEND BUN_RAW_SOURCES "${BUN_WORKDIR}/codegen/ZigGeneratedClasses.cpp") if(NOT NO_CODEGEN) # --- ErrorCode Generator --- file(GLOB NODE_ERRORS_TS ${CONFIGURE_DEPENDS} "${BUN_SRC}/bun.js/bindings/ErrorCode.ts" ) add_custom_command( OUTPUT "${BUN_WORKDIR}/codegen/ErrorCode+List.h" "${BUN_WORKDIR}/codegen/ErrorCode+Data.h" "${BUN_WORKDIR}/codegen/ErrorCode.zig" COMMAND ${BUN_EXECUTABLE} run "${BUN_CODEGEN_SRC}/generate-node-errors.ts" "${BUN_WORKDIR}/codegen" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} MAIN_DEPENDENCY "${BUN_CODEGEN_SRC}/generate-node-errors.ts" DEPENDS ${NODE_ERRORS_TS} VERBATIM COMMENT "Generating ErrorCode.zig" ) # This needs something to force it to be regenerated WEBKIT_ADD_SOURCE_DEPENDENCIES( "${BUN_SRC}/bun.js/bindings/ErrorCode.cpp" "${BUN_WORKDIR}/codegen/ErrorCode+List.h" ) WEBKIT_ADD_SOURCE_DEPENDENCIES( "${BUN_SRC}/bun.js/bindings/ErrorCode.h" "${BUN_WORKDIR}/codegen/ErrorCode+Data.h" ) endif() # --- JSSink Generator --- add_custom_command( OUTPUT "${BUN_WORKDIR}/codegen/JSSink.cpp" "${BUN_WORKDIR}/codegen/JSSink.h" COMMAND ${BUN_EXECUTABLE} run "src/codegen/generate-jssink.ts" "${BUN_WORKDIR}/codegen" VERBATIM MAIN_DEPENDENCY "src/codegen/generate-jssink.ts" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Generating JSSink" USES_TERMINAL ) list(APPEND BUN_RAW_SOURCES "${BUN_WORKDIR}/codegen/JSSink.cpp") # --- .lut.h Generator --- set(BUN_OBJECT_LUT_SOURCES bun.js/bindings/BunObject.cpp bun.js/bindings/ZigGlobalObject.lut.txt bun.js/bindings/JSBuffer.cpp bun.js/bindings/BunProcess.cpp bun.js/bindings/ProcessBindingConstants.cpp bun.js/bindings/ProcessBindingNatives.cpp ) set(BUN_OBJECT_LUT_OUTPUTS "") set(BUN_HASH_LUT_GENERATOR "${BUN_CODEGEN_SRC}/create-hash-table.ts") if(NOT BUN_LINK_ONLY) macro(GENERATE_HASH_LUT _input _output _display_name) if(NOT NO_CODEGEN) add_custom_command( OUTPUT ${_output} MAIN_DEPENDENCY ${BUN_HASH_LUT_GENERATOR} DEPENDS ${_input} COMMAND ${BUN_EXECUTABLE} run ${BUN_HASH_LUT_GENERATOR} ${_input} ${_output} VERBATIM COMMENT "Generating ${_display_name}" ) endif() list(APPEND BUN_OBJECT_LUT_OUTPUTS "${_output}") # list(APPEND Bun_HEADERS ${_output}) WEBKIT_ADD_SOURCE_DEPENDENCIES(${_input} ${_output}) endmacro() foreach(_file ${BUN_OBJECT_LUT_SOURCES}) if(NOT EXISTS "${BUN_SRC}/${_file}") message(FATAL_ERROR "Could not find ${_file} needed for LUT generation") endif() get_filename_component(_name ${_file} NAME_WE) # workaround for ZigGlobalObject if(_name MATCHES "ZigGlobalObject") set(_name "ZigGlobalObject") endif() GENERATE_HASH_LUT(${BUN_SRC}/${_file} ${BUN_WORKDIR}/codegen/${_name}.lut.h ${_name}.lut.h) endforeach() WEBKIT_ADD_SOURCE_DEPENDENCIES(${BUN_SRC}/bun.js/bindings/ZigGlobalObject.cpp ${BUN_WORKDIR}/codegen/ZigGlobalObject.lut.h) endif() # --- Identifier Cache --- if(NOT NO_CODEGEN) set(BUN_IDENTIFIER_CACHE_OUT "${BUN_SRC}/js_lexer/id_continue_bitset.blob" "${BUN_SRC}/js_lexer/id_continue_bitset.meta.blob" "${BUN_SRC}/js_lexer/id_start_bitset.blob" "${BUN_SRC}/js_lexer/id_start_bitset.meta.blob") add_custom_command( OUTPUT ${BUN_IDENTIFIER_CACHE_OUT} MAIN_DEPENDENCY "${BUN_SRC}/js_lexer/identifier_data.zig" DEPENDS "${BUN_SRC}/js_lexer/identifier_cache.zig" COMMAND ${ZIG_COMPILER} run "--zig-lib-dir" "${ZIG_LIB_DIR}" "--cache-dir" "${LOCAL_ZIG_CACHE_DIR}" "--global-cache-dir" "${GLOBAL_ZIG_CACHE_DIR}" "${BUN_SRC}/js_lexer/identifier_data.zig" VERBATIM COMMENT "Building Identifier Cache" ) endif() # --- Bundled TS/JS --- # Note: It's not worth doing this in parallel at the CMake/Ninja level, because this bundling # requires all the JS files to be known, but also Bun will use all cores during bundling anyways. if(NOT NO_CODEGEN) file(GLOB BUN_TS_MODULES ${CONFIGURE_DEPENDS} "${BUN_SRC}/js/node/*.ts" "${BUN_SRC}/js/node/*.js" "${BUN_SRC}/js/bun/*.ts" "${BUN_SRC}/js/bun/*.js" "${BUN_SRC}/js/builtins/*.ts" "${BUN_SRC}/js/builtins/*.js" "${BUN_SRC}/js/thirdparty/*.js" "${BUN_SRC}/js/thirdparty/*.ts" "${BUN_SRC}/js/internal/*.js" "${BUN_SRC}/js/internal/*.ts" "${BUN_SRC}/js/internal/util/*.js" "${BUN_SRC}/js/internal/fs/*.ts" "${BUN_SRC}/js/node/*.js" "${BUN_SRC}/js/node/*.ts" "${BUN_SRC}/js/thirdparty/*.js" "${BUN_SRC}/js/thirdparty/*.ts" "${BUN_SRC}/js/internal-for-testing.ts" ) file(GLOB CODEGEN_FILES ${CONFIGURE_DEPENDS} "${BUN_CODEGEN_SRC}/*.ts") add_custom_command( OUTPUT "${BUN_WORKDIR}/codegen/WebCoreJSBuiltins.cpp" "${BUN_WORKDIR}/codegen/WebCoreJSBuiltins.h" "${BUN_WORKDIR}/codegen/InternalModuleRegistryConstants.h" "${BUN_WORKDIR}/codegen/InternalModuleRegistry+createInternalModuleById.h" "${BUN_WORKDIR}/codegen/InternalModuleRegistry+enum.h" "${BUN_WORKDIR}/codegen/InternalModuleRegistry+numberOfModules.h" "${BUN_WORKDIR}/codegen/NativeModuleImpl.h" "${BUN_WORKDIR}/codegen/ResolvedSourceTag.zig" "${BUN_WORKDIR}/codegen/SyntheticModuleType.h" "${BUN_WORKDIR}/codegen/GeneratedJS2Native.h" "${BUN_SRC}/bun.js/bindings/GeneratedJS2Native.zig" COMMAND ${BUN_EXECUTABLE} run "${BUN_SRC}/codegen/bundle-modules.ts" "--debug=${DEBUG}" "${BUN_WORKDIR}" DEPENDS ${BUN_TS_MODULES} ${CODEGEN_FILES} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Bundling JS" ) endif() WEBKIT_ADD_SOURCE_DEPENDENCIES( "${BUN_SRC}/bun.js/bindings/InternalModuleRegistry.cpp" "${BUN_WORKDIR}/codegen/InternalModuleRegistryConstants.h" ) list(APPEND BUN_RAW_SOURCES "${BUN_WORKDIR}/codegen/WebCoreJSBuiltins.cpp") # --- Peechy API --- # if(NOT NO_CODEGEN) # add_custom_command( # OUTPUT "${BUN_SRC}/api/schema.js" # "${BUN_SRC}/api/schema.d.ts" # "${BUN_SRC}/api/schema.zig" # WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" # COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/node_modules/.bin/peechy" # "--schema" "${BUN_SRC}/api/schema.peechy" # "--esm" "${BUN_SRC}/api/schema.js" # "--ts" "${BUN_SRC}/api/schema.d.ts" # "--zig" "${BUN_SRC}/api/schema.zig" # COMMAND "${ZIG_COMPILER}" "fmt" "src/api/schema.zig" # COMMAND "${PRETTIER}" "--config=.prettierrc.cjs" "--write" "src/api/schema.js" "src/api/schema.d.ts" # DEPENDS "${BUN_SRC}/api/schema.peechy" # COMMENT "Building schema" # ) # add_custom_command( # OUTPUT "${BUN_SRC}/analytics/analytics_schema.zig" # WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" # COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/node_modules/.bin/peechy" # "--schema" "${BUN_SRC}/analytics/schema.peechy" # "--zig" "${BUN_SRC}/analytics/analytics_schema.zig" # COMMAND "${ZIG_COMPILER}" "fmt" "${BUN_SRC}/analytics/analytics_schema.zig" # DEPENDS "${BUN_SRC}/api/schema.peechy" # COMMENT "Building analytics_schema.zig" # ) # endif() # --- Runtime.js --- if(NOT NO_CODEGEN) add_custom_command( OUTPUT "src/fallback.out.js" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND "${ESBUILD}" "--target=esnext" "--bundle" "src/fallback.ts" "--format=iife" "--platform=browser" "--minify" "--outfile=src/fallback.out.js" DEPENDS "src/fallback.ts" ) endif() # --- Zig Object --- file(GLOB ZIG_FILES "${BUN_SRC}/*.zig" "${BUN_SRC}/*/*.zig" "${BUN_SRC}/*/*/*.zig" "${BUN_SRC}/*/*/*/*.zig" "${BUN_SRC}/*/*/*/*/*.zig" ) if(NOT BUN_ZIG_OBJ_FORMAT) # To use LLVM bitcode from Zig, more work needs to be done. Currently, an install of # LLVM 18.1.7 does not compatible with what bitcode Zig 0.13 outputs (has LLVM 18.1.7) # Change to "bc" to experiment, "Invalid record" means it is not valid output. set(BUN_ZIG_OBJ_FORMAT "obj") endif() if(NOT BUN_ZIG_OBJ_DIR) set(BUN_ZIG_OBJ_DIR "${BUN_WORKDIR}/CMakeFiles") endif() get_filename_component(BUN_ZIG_OBJ_DIR "${BUN_ZIG_OBJ_DIR}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") if(WIN32) set(BUN_ZIG_OBJ "${BUN_ZIG_OBJ_DIR}/bun-zig.o") else() set(BUN_ZIG_OBJ "${BUN_ZIG_OBJ_DIR}/bun-zig.o") endif() set(USES_TERMINAL_NOT_IN_CI "") if(NOT CI) set(USES_TERMINAL_NOT_IN_CI "USES_TERMINAL") endif() if(NOT BUN_LINK_ONLY AND NOT BUN_CPP_ONLY) add_custom_command( OUTPUT "${BUN_ZIG_OBJ}" COMMAND "${ZIG_COMPILER}" "build" "obj" "--zig-lib-dir" "${ZIG_LIB_DIR}" "--prefix" "${BUN_ZIG_OBJ_DIR}" "--verbose" "-Dgenerated-code=${BUN_WORKDIR}/codegen" "-freference-trace=10" "-Dversion=${Bun_VERSION}" "-Dcanary=${CANARY}" "-Doptimize=${ZIG_OPTIMIZE}" "-Dcpu=${CPU_TARGET}" "-Dtarget=${ZIG_TARGET}" "-Denable_logs=${ENABLE_LOGS}" "-Dreported_nodejs_version=${REPORTED_NODEJS_VERSION}" "-Dobj_format=${BUN_ZIG_OBJ_FORMAT}" "--cache-dir" "${LOCAL_ZIG_CACHE_DIR}" "--global-cache-dir" "${GLOBAL_ZIG_CACHE_DIR}" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/build.zig" "${ZIG_FILES}" "${BUN_WORKDIR}/codegen/ZigGeneratedClasses.zig" "${BUN_WORKDIR}/codegen/ErrorCode.zig" "${BUN_WORKDIR}/codegen/ResolvedSourceTag.zig" "${BUN_IDENTIFIER_CACHE_OUT}" "${BUN_SRC}/api/schema.zig" "${BUN_SRC}/bun.js/bindings/GeneratedJS2Native.zig" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Building zig code" VERBATIM # This is here to show Zig's progress indicator ${USES_TERMINAL_NOT_IN_CI} ) endif() if(WIN32) list(APPEND BUN_RAW_SOURCES "${BUN_SRC}/bun.js/bindings/windows/musl-memmem.c") include_directories("${BUN_SRC}/bun.js/bindings/windows") endif() if(NOT BUN_CPP_ARCHIVE) # TODO: unified sources set(BUN_SOURCES ${BUN_RAW_SOURCES}) else() # used by ci set(BUN_SOURCES "") add_link_options("${BUN_CPP_ARCHIVE}") endif() # -- Windows resources (app icon) -- if(CANARY GREATER 0) set(Bun_VERSION_WITH_TAG "${Bun_VERSION}-canary.${CANARY}") else() set(Bun_VERSION_WITH_TAG "${Bun_VERSION}") endif() if(WIN32) set(BUN_ICO_PATH "${BUN_SRC}/bun.ico") configure_file("${BUN_SRC}/windows-app-info.rc" "${BUN_WORKDIR}/CMakeFiles/windows-app-info.rc") list(APPEND BUN_SOURCES "${BUN_WORKDIR}/CMakeFiles/windows-app-info.rc") endif() # -- The Buntime™️ --- if(BUN_TIDY_ONLY OR BUN_TIDY_ONLY_EXTRA) add_library(${bun} OBJECT "${BUN_SOURCES}") elseif(NOT BUN_CPP_ONLY) add_executable(${bun} "${BUN_SOURCES}" "${BUN_ZIG_OBJ}") else() add_executable(${bun} "${BUN_SOURCES}") endif() set_target_properties(${bun} PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS YES CXX_VISIBILITY_PRESET hidden C_STANDARD 17 C_STANDARD_REQUIRED YES VISIBILITY_INLINES_HIDDEN YES ) if(APPLE) add_compile_definitions("__DARWIN_NON_CANCELABLE=1") endif() add_compile_definitions( # TODO: are all of these variables strictly necessary? "_HAS_EXCEPTIONS=0" "LIBUS_USE_OPENSSL=1" "LIBUS_USE_BORINGSSL=1" "WITH_BORINGSSL=1" "STATICALLY_LINKED_WITH_JavaScriptCore=1" "STATICALLY_LINKED_WITH_BMALLOC=1" "BUILDING_WITH_CMAKE=1" "JSC_OBJC_API_ENABLED=0" "BUN_SINGLE_THREADED_PER_VM_ENTRY_SCOPE=1" "NAPI_EXPERIMENTAL=ON" "NOMINMAX" "IS_BUILD" "BUILDING_JSCONLY__" "BUN_DYNAMIC_JS_LOAD_PATH=\"${BUN_WORKDIR}/js\"" "REPORTED_NODEJS_VERSION=\"${REPORTED_NODEJS_VERSION}\"" "REPORTED_NODEJS_ABI_VERSION=${REPORTED_NODEJS_ABI_VERSION}" ) if(NOT ASSERT_ENABLED) if(APPLE) add_compile_definitions("_LIBCXX_ENABLE_ASSERTIONS=0") add_compile_definitions("_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE") endif() add_compile_definitions("NDEBUG=1") else() if(APPLE) add_compile_definitions("_LIBCXX_ENABLE_ASSERTIONS=1") add_compile_definitions("_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG") elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") add_compile_definitions("_GLIBCXX_ASSERTIONS=1") endif() add_compile_definitions("ASSERT_ENABLED=1") endif() if(ICU_INCLUDE_DIR) include_directories(${ICU_INCLUDE_DIR}) endif() include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/packages/ ${CMAKE_CURRENT_SOURCE_DIR}/packages/bun-usockets ${CMAKE_CURRENT_SOURCE_DIR}/packages/bun-usockets/src ${CMAKE_CURRENT_SOURCE_DIR}/src/bun.js/bindings ${CMAKE_CURRENT_SOURCE_DIR}/src/bun.js/bindings/webcore ${CMAKE_CURRENT_SOURCE_DIR}/src/bun.js/bindings/webcrypto ${CMAKE_CURRENT_SOURCE_DIR}/src/bun.js/bindings/sqlite ${CMAKE_CURRENT_SOURCE_DIR}/src/bun.js/modules ${CMAKE_CURRENT_SOURCE_DIR}/src/js/builtins ${CMAKE_CURRENT_SOURCE_DIR}/src/napi ${CMAKE_CURRENT_SOURCE_DIR}/src/deps ${CMAKE_CURRENT_SOURCE_DIR}/src/deps/picohttpparser ${WEBKIT_INCLUDE_DIR} "${BUN_WORKDIR}/codegen" ) # -- BUN_CPP_ONLY Target if(NOT BUN_CPP_ARCHIVE) if(BUN_CPP_ONLY) if(NOT WIN32) string(REPLACE ";" ".o\n " BUN_OBJECT_LIST "${BUN_SOURCES}.o") string(REPLACE "${BUN_WORKDIR}/" "CMakeFiles/${bun}.dir/" BUN_OBJECT_LIST "${BUN_OBJECT_LIST}") string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "CMakeFiles/${bun}.dir/" BUN_OBJECT_LIST "${BUN_OBJECT_LIST}") write_file("${BUN_WORKDIR}/compile-cpp-only.sh" "#!/usr/bin/env bash\n" "# this file is generated in CMakeLists.txt\n" "set -ex\n" "OBJ_LIST=(\n ${BUN_OBJECT_LIST}\n)\n" "ninja \${OBJ_LIST[@]} $@\n" "\"${AR}\" rcvs bun-cpp-objects.a \${OBJ_LIST[@]}\n" "echo '-> bun-cpp-objects.a'\n" ) else() string(REPLACE ";" ".obj\",\n \"" BUN_OBJECT_LIST "\"${BUN_SOURCES}.obj\"") string(REPLACE "rc.obj" "rc.res" BUN_OBJECT_LIST "${BUN_OBJECT_LIST}") string(REPLACE "${BUN_WORKDIR}/" "CMakeFiles/${bun}.dir/" BUN_OBJECT_LIST "${BUN_OBJECT_LIST}") string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "CMakeFiles/${bun}.dir/" BUN_OBJECT_LIST "${BUN_OBJECT_LIST}") write_file("${BUN_WORKDIR}/compile-cpp-only.ps1" "# this file is generated in CMakeLists.txt\n" "$ErrorActionPreference = \"Stop\"\n" "$ObjectFiles=@(\n ${BUN_OBJECT_LIST}\n)\n" "ninja @ObjectFiles @args\n" "& \"${AR}\" rcvs bun-cpp-objects.a @ObjectFiles\n" "Write-Host '-> bun-cpp-objects.a'\n" ) endif() endif() else() set_target_properties(${bun} PROPERTIES LINKER_LANGUAGE CXX) endif() # --- clang and linker flags --- if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(NOT WIN32) target_compile_options(${bun} PUBLIC -O0 -g -g3 -ggdb -gdwarf-4 -Werror=return-type -Werror=return-stack-address -Werror=implicit-function-declaration -Werror=uninitialized -Werror=conditional-uninitialized -Werror=suspicious-memaccess -Werror=int-conversion -Werror=nonnull -Werror=move -Werror=sometimes-uninitialized -Werror=unused -Wno-unused-function -Wno-nullability-completeness -Werror -fsanitize=null -fsanitize-recover=all -fsanitize=bounds -fsanitize=return -fsanitize=nullability-arg -fsanitize=nullability-assign -fsanitize=nullability-return -fsanitize=returns-nonnull-attribute -fsanitize=unreachable ) target_link_libraries(${bun} PRIVATE -fsanitize=null) else() target_compile_options(${bun} PUBLIC /Od /Z7) endif() add_compile_definitions("BUN_DEBUG=1") elseif(CMAKE_BUILD_TYPE STREQUAL "Release") set(LTO_FLAG "") if(NOT WIN32) if(USE_LTO) list(APPEND LTO_FLAG "-flto=full" "-emit-llvm" "-fwhole-program-vtables" "-fforce-emit-vtables") endif() # Leave -Werror=unused off in release builds so we avoid errors from being used in ASSERT target_compile_options(${bun} PUBLIC -O3 ${LTO_FLAG} -g1 -Werror=return-type -Werror=return-stack-address -Werror=implicit-function-declaration -Werror=uninitialized -Werror=conditional-uninitialized -Werror=suspicious-memaccess -Werror=int-conversion -Werror=nonnull -Werror=move -Werror=sometimes-uninitialized -Wno-nullability-completeness -Werror ) else() set(LTO_LINK_FLAG "") if(USE_LTO) target_compile_options(${bun} PUBLIC -Xclang -emit-llvm-bc) list(APPEND LTO_FLAG "-flto=full") list(APPEND LTO_LINK_FLAG "-flto=full") list(APPEND LTO_LINK_FLAG "/LTCG") list(APPEND LTO_LINK_FLAG "/OPT:REF") list(APPEND LTO_LINK_FLAG "/OPT:NOICF") endif() target_compile_options(${bun} PUBLIC /O2 ${LTO_FLAG} /Gy /Gw /GF /GA ) target_link_options(${bun} PUBLIC ${LTO_LINK_FLAG} /DEBUG:FULL /delayload:ole32.dll /delayload:WINMM.dll /delayload:dbghelp.dll /delayload:VCRUNTIME140_1.dll # libuv loads these two immediately, but for some reason it seems to still be slightly faster to delayload them /delayload:WS2_32.dll /delayload:WSOCK32.dll /delayload:ADVAPI32.dll /delayload:IPHLPAPI.dll ) endif() endif() if(NOT CI AND NOT WIN32) target_compile_options(${bun} PRIVATE -fdiagnostics-color=always) endif() if(NOT CPU_TARGET STREQUAL "native") # passing -march=native to clang will break older systems # by default on x64, CPU_TARGET is set to "haswell" or "nehalem" depending on baseline # on arm, this argument will not be passed. target_compile_options(${bun} PUBLIC "-march=${CPU_TARGET}") else() if(APPLE AND ARCH STREQUAL "aarch64") # On arm macOS, we can set it to a minimum of the M1 cpu set. this might be the default already. target_compile_options(${bun} PUBLIC "-mcpu=apple-m1") endif() if(NOT WIN32 AND NOT APPLE AND ARCH STREQUAL "aarch64") # on arm64 linux, we set a minimum of armv8 target_compile_options(${bun} PUBLIC -march=armv8-a+crc -mtune=ampere1) endif() endif() target_compile_options(${bun} PUBLIC -ferror-limit=${ERROR_LIMIT}) if(WIN32) add_compile_definitions( "WIN32" "_WINDOWS" "WIN32_LEAN_AND_MEAN=1" "_CRT_SECURE_NO_WARNINGS" "BORINGSSL_NO_CXX=1" # lol ) # set_property(TARGET ${bun} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") set_property(TARGET ${bun} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded") target_compile_options(${bun} PUBLIC "/EHsc" "/GR-" -Xclang -fno-c++-static-destructors) target_link_options(${bun} PUBLIC "/STACK:0x1200000,0x100000" "/DEF:${BUN_SRC}/symbols.def" "/errorlimit:0") else() target_compile_options(${bun} PUBLIC -mtune=${CPU_TARGET} -fconstexpr-steps=2542484 -fconstexpr-depth=54 -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-c++-static-destructors -fvisibility=hidden -fvisibility-inlines-hidden -fno-rtti -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -fno-pic -fno-pie -faddrsig -ffile-prefix-map="${CMAKE_CURRENT_SOURCE_DIR}"=. -ffile-prefix-map="${BUN_DEPS_DIR}"=src/deps -ffile-prefix-map="${BUN_DEPS_OUT_DIR}"=src/deps ) endif() if(APPLE) target_link_options(${bun} PUBLIC "-dead_strip") target_link_options(${bun} PUBLIC "-dead_strip_dylibs") target_link_options(${bun} PUBLIC "-Wl,-stack_size,0x1200000") target_link_options(${bun} PUBLIC "-exported_symbols_list" "${BUN_SRC}/symbols.txt") set_target_properties(${bun} PROPERTIES LINK_DEPENDS "${BUN_SRC}/symbols.txt") target_link_options(${bun} PUBLIC "-fno-keep-static-consts") target_link_libraries(${bun} PRIVATE "resolv") endif() if(UNIX AND NOT APPLE) target_link_options(${bun} PUBLIC -fuse-ld=lld-${LLVM_VERSION} -fno-pic -static-libstdc++ -static-libgcc "-Wl,-no-pie" "-Wl,-icf=safe" "-Wl,--as-needed" "-Wl,--gc-sections" "-Wl,-z,stack-size=12800000" "-Wl,--wrap=fcntl" "-Wl,--wrap=fcntl64" "-Wl,--wrap=stat64" "-Wl,--wrap=pow" "-Wl,--wrap=exp" "-Wl,--wrap=expf" "-Wl,--wrap=log" "-Wl,--wrap=log2" "-Wl,--wrap=lstat" "-Wl,--wrap=stat64" "-Wl,--wrap=stat" "-Wl,--wrap=fstat" "-Wl,--wrap=fstatat" "-Wl,--wrap=lstat64" "-Wl,--wrap=fstat64" "-Wl,--wrap=fstatat64" "-Wl,--wrap=mknod" "-Wl,--wrap=mknodat" "-Wl,--wrap=statx" "-Wl,--wrap=fmod" "-Wl,--compress-debug-sections=zlib" "-Bsymbolics-functions" "-rdynamic" "-Wl,--dynamic-list=${BUN_SRC}/symbols.dyn" "-Wl,--version-script=${BUN_SRC}/linker.lds" -Wl,-z,lazy -Wl,-z,norelro ) target_link_libraries(${bun} PRIVATE "c") target_link_libraries(${bun} PRIVATE "pthread") target_link_libraries(${bun} PRIVATE "dl") if(NOT USE_STATIC_LIBATOMIC) target_link_libraries(${bun} PUBLIC "libatomic.so") else() target_link_libraries(${bun} PRIVATE "libatomic.a") endif() if(USE_SYSTEM_ICU) target_link_libraries(${bun} PRIVATE "libicudata.a") target_link_libraries(${bun} PRIVATE "libicui18n.a") target_link_libraries(${bun} PRIVATE "libicuuc.a") else() target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libicudata.a") target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libicui18n.a") target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libicuuc.a") endif() set_target_properties(${bun} PROPERTIES LINK_DEPENDS "${BUN_SRC}/linker.lds") set_target_properties(${bun} PROPERTIES LINK_DEPENDS "${BUN_SRC}/symbols.dyn") endif() # --- ICU --- if(APPLE) target_link_libraries(${bun} PRIVATE "icucore") endif() # --- Stripped Binary "bun" if(CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT WIN32 AND NOT ASSERT_ENABLED) # if(CI AND APPLE) if(APPLE) add_custom_command( TARGET ${bun} POST_BUILD COMMAND ${DSYMUTIL} -o ${BUN_WORKDIR}/${bun}.dSYM ${BUN_WORKDIR}/${bun} COMMENT "Generating .dSYM" ) endif() add_custom_command( TARGET ${bun} POST_BUILD COMMAND ${STRIP} -s -x -S -o ${BUN_WORKDIR}/bun ${BUN_WORKDIR}/${bun} COMMENT "Stripping Symbols" ) endif() if(WIN32) # Kill all instances of bun before linking. # This is necessary because the file is locked by the process. add_custom_command( TARGET ${bun} PRE_LINK COMMAND "powershell" "/C" "Stop-Process -Name '${bun}' -Force -ErrorAction SilentlyContinue; exit 0" ) endif() # --- Dependencies --- if(USE_CUSTOM_ZLIB) include_directories(${BUN_DEPS_DIR}/zlib) if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/zlib.lib") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libz.a") endif() else() if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_DIR}/zlib_maybethisworks.lib") else() find_package(ZLIB REQUIRED) target_link_libraries(${bun} PRIVATE ZLIB::ZLIB) endif() endif() if(USE_CUSTOM_BORINGSSL) include_directories(${BUN_DEPS_DIR}/boringssl/include) if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/crypto.lib") target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/ssl.lib") target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/decrepit.lib") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libcrypto.a") target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libssl.a") target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libdecrepit.a") endif() else() include(FindBoringSSL) FindBoringSSL(${bun}) endif() if(USE_CUSTOM_LIBARCHIVE) include_directories(${BUN_DEPS_DIR}/libarchive/include) if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/archive.lib") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libarchive.a") endif() else() find_package(LibArchive REQUIRED) target_link_libraries(${bun} PRIVATE LibArchive::LibArchive) endif() if(USE_CUSTOM_LIBDEFLATE) include_directories(${BUN_DEPS_DIR}/libdeflate) if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/deflate.lib") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libdeflate.a") endif() else() find_package(LibDeflate REQUIRED) target_link_libraries(${bun} PRIVATE LibDeflate::LibDeflate) endif() if(USE_CUSTOM_MIMALLOC) include_directories(${BUN_DEPS_DIR}/mimalloc/include) if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/mimalloc.lib") elseif(APPLE) if(USE_DEBUG_JSC OR CMAKE_BUILD_TYPE STREQUAL "Debug") message(STATUS "Using debug mimalloc") target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libmimalloc-debug.o") else() # Note: https://github.com/microsoft/mimalloc/issues/512 # It may have been a bug in our code at the time. target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libmimalloc.o") endif() else() if(USE_DEBUG_JSC OR CMAKE_BUILD_TYPE STREQUAL "Debug") message(STATUS "Using debug mimalloc") target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libmimalloc-debug.a") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libmimalloc.o") endif() endif() else() find_package(mimalloc REQUIRED) target_link_libraries(${bun} PRIVATE mimalloc) endif() if(USE_CUSTOM_ZSTD) include_directories(${BUN_DEPS_DIR}/zstd/include) if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/zstd.lib") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libzstd.a") endif() else() find_package(zstd CONFIG REQUIRED) target_link_libraries(${bun} PRIVATE zstd::libzstd) endif() if(USE_CUSTOM_CARES) include_directories(${BUN_DEPS_DIR}/c-ares/include) if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/cares.lib") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libcares.a") endif() else() find_package(c-ares CONFIG REQUIRED) target_link_libraries(${bun} PRIVATE c-ares::cares) endif() if(USE_CUSTOM_TINYCC) if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/tcc.lib") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libtcc.a") endif() else() find_package(tinycc REQUIRED) target_link_libraries(${bun} PRIVATE tinycc::tinycc) endif() if(USE_CUSTOM_LOLHTML) if(WIN32) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/lolhtml.lib") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/liblolhtml.a") endif() else() find_package(lolhtml REQUIRED) target_link_libraries(${bun} PRIVATE lolhtml::lolhtml) endif() if(WIN32) if(USE_CUSTOM_LIBUV) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libuv.lib") include_directories(${bun} PRIVATE "${BUN_DEPS_DIR}/libuv/include") else() find_package(libuv CONFIG REQUIRED) target_link_libraries(${bun} PRIVATE $,libuv::uv_a,libuv::uv>) endif() endif() if(USE_STATIC_SQLITE) add_library(sqlite3 STATIC src/bun.js/bindings/sqlite/sqlite3.c) target_include_directories(sqlite3 PUBLIC src/bun.js/bindings/sqlite) target_compile_definitions(sqlite3 PRIVATE "SQLITE_ENABLE_COLUMN_METADATA=" "SQLITE_MAX_VARIABLE_NUMBER=250000" "SQLITE_ENABLE_RTREE=1" "SQLITE_ENABLE_FTS3=1" "SQLITE_ENABLE_FTS3_PARENTHESIS=1" "SQLITE_ENABLE_FTS5=1" "SQLITE_ENABLE_JSON1=1" "SQLITE_ENABLE_MATH_FUNCTIONS=1" ) if(WIN32) target_compile_options(sqlite3 PRIVATE /MT /U_DLL) endif() target_link_libraries(${bun} PRIVATE sqlite3) message(STATUS "Using static sqlite3") target_compile_definitions(${bun} PRIVATE "LAZY_LOAD_SQLITE=0") else() message(STATUS "Using dynamicly linked sqlite3") target_compile_definitions(${bun} PRIVATE "LAZY_LOAD_SQLITE=1") endif() # -- Brotli -- set(BROTLI_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/deps/brotli") file(GLOB BROTLI_FILES ${CONFIGURE_DEPENDS} "${BROTLI_SRC}/common/*.c" "${BROTLI_SRC}/enc/*.c" "${BROTLI_SRC}/dec/*.c" ) add_library(brotli STATIC ${BROTLI_FILES}) target_include_directories(brotli PRIVATE "${BROTLI_SRC}/include") target_compile_definitions(brotli PRIVATE "BROTLI_STATIC") if(WIN32) target_compile_options(brotli PRIVATE /MT /U_DLL) endif() target_link_libraries(${bun} PRIVATE brotli) include_directories("${BUN_DEPS_DIR}/brotli/include") if(USE_CUSTOM_LSHPACK) include_directories(${BUN_DEPS_DIR}/ls-hpack) if(WIN32) include_directories(${BUN_DEPS_DIR}/ls-hpack/compat/queue) target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/lshpack.lib") else() target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/liblshpack.a") endif() else() find_package(lshpack REQUIRED) target_link_libraries(${bun} PRIVATE lshpack) endif() if(NOT WIN32) target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libWTF.a") target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libJavaScriptCore.a") if(NOT APPLE OR EXISTS "${WEBKIT_LIB_DIR}/libbmalloc.a") target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libbmalloc.a") endif() else() target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/WTF.lib" "${WEBKIT_LIB_DIR}/JavaScriptCore.lib" "${WEBKIT_LIB_DIR}/sicudt.lib" "${WEBKIT_LIB_DIR}/sicuin.lib" "${WEBKIT_LIB_DIR}/sicuuc.lib" winmm bcrypt ntdll userenv dbghelp wsock32 # ws2_32 required by TransmitFile aka sendfile on windows delayimp.lib ) endif() if(BUN_LINK_ONLY) message(STATUS "NOTE: BUN_LINK_ONLY is ON, this build config will only link the Bun executable") endif() if(BUN_CPP_ONLY) message(STATUS "NOTE: BUN_CPP_ONLY is ON, this build will only work with 'compile-cpp-only.${SCRIPT_EXTENSION}'") endif() if(NO_CODEGEN) message(STATUS "NOTE: NO_CODEGEN is ON, this build expects ./codegen to exist") endif() if(BUN_TIDY_ONLY) find_program(CLANG_TIDY_EXE NAMES "clang-tidy") set(CLANG_TIDY_COMMAND "${CLANG_TIDY_EXE}" "-checks=-*,clang-analyzer-*,-clang-analyzer-webkit.UncountedLambdaCapturesChecker,-clang-analyzer-optin.core.EnumCastOutOfRange" "--fix" "--fix-errors" "--format-style=webkit" "--warnings-as-errors=*") set_target_properties(${bun} PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}") endif() if(BUN_TIDY_ONLY_EXTRA) find_program(CLANG_TIDY_EXE NAMES "clang-tidy") # -clang-analyzer-optin.core.EnumCastOutOfRange is disabled because it's too noisy, e.g. for JavaScriptCore/Lookup.h set(CLANG_TIDY_COMMAND "${CLANG_TIDY_EXE}" "-checks=-*,clang-analyzer-*,performance-*,-clang-analyzer-webkit.UncountedLambdaCapturesChecker,-clang-analyzer-optin.core.EnumCastOutOfRange" "--fix" "--fix-errors" "--format-style=webkit" "--warnings-as-errors=*") set_target_properties(${bun} PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}") endif()