output_dir = "%{cfg.buildcfg}-%{cfg.system}" llvm_version = "22.1.0" llvm_vendored_dir = "ext/llvm" host_arm = os.hostarch() == "ARM64" or os.hostarch() == "arm64" host_architecture = host_arm and "ARM64" or "x64" function llvm_release_asset() local host = os.host() if host == "macosx" then return host_arm and ("LLVM-" .. llvm_version .. "-macOS-ARM64.tar.xz") or nil elseif host == "linux" then return "LLVM-" .. llvm_version .. (host_arm and "-Linux-ARM64" or "-Linux-X64") .. ".tar.xz" elseif host == "windows" then return "clang+llvm-" .. llvm_version .. (host_arm and "-aarch64-pc-windows-msvc" or "-x86_64-pc-windows-msvc") .. ".tar.xz" end return nil end function llvm_prefix() local function usable(candidate) if candidate == nil or candidate == "" then return nil end local prefix = path.getabsolute( (candidate:gsub("%s+$", "")):gsub("\\", "/"), _MAIN_SCRIPT_DIR ) return os.isdir(prefix .. "/include/lldb") and prefix or nil end local function newest_of(pattern) local matches = os.matchdirs(pattern) table.sort(matches) for index = #matches, 1, -1 do local prefix = usable(matches[index]) if prefix ~= nil then return prefix end end return nil end local prefix = usable(os.getenv("LLVM_PREFIX")) or usable(llvm_vendored_dir) or usable(os.outputof("llvm-config --prefix")) if prefix == nil and os.host() == "windows" then prefix = usable( os.getenv("ProgramFiles") and os.getenv("ProgramFiles") .. "/LLVM" ) or newest_of("C:/Program Files/LLVM*") end if prefix == nil and os.host() == "macosx" then prefix = usable(os.outputof("brew --prefix llvm")) end if prefix == nil and os.host() == "linux" then prefix = newest_of("/usr/lib/llvm-*") or newest_of("/usr/local/llvm*") end return prefix end llvm_dir = llvm_prefix() if llvm_dir == nil and _ACTION ~= nil and _ACTION ~= "fetch-llvm" and _ACTION ~= "clean" and _ACTION ~= "check" then error( "no llvm with lldb headers found. install one and set LLVM_PREFIX, " .. "or run `premake5 fetch-llvm` to download the pinned " .. llvm_version .. " release" ) end llvm_dir = llvm_dir or "" include_dir = { glfw = "ext/glfw/include", glad = "ext/glad/include", imgui = "ext/imgui", imgui_backends = "ext/imgui/backends", lldb = llvm_dir .. "/include", } library_dir = { lldb = llvm_dir .. "/lib", } function lldb_library() if llvm_dir == "" then return "" end local names = { "liblldb.so" } if os.target() == "windows" then names = { "liblldb.lib" } elseif os.target() == "macosx" then names = { "liblldb.dylib" } end for _, name in ipairs(names) do local candidate = library_dir.lldb .. "/" .. name if os.isfile(candidate) then return candidate end end local versioned = os.matchfiles( library_dir.lldb .. "/liblldb.so.*" ) table.sort(versioned) if versioned[#versioned] ~= nil then return versioned[#versioned] end if os.target() ~= os.host() then return library_dir.lldb .. "/" .. names[1] end error( "llvm at " .. llvm_dir .. " has lldb headers but no liblldb in " .. library_dir.lldb ) end function windows_runtime_copies() local commands = {} if llvm_dir == "" then return commands end local runtimes = os.matchfiles( llvm_dir .. "/bin/liblldb.dll" ) for _, runtime in ipairs( os.matchfiles(llvm_dir .. "/bin/python*.dll") ) do table.insert(runtimes, runtime) end if #runtimes == 0 then runtimes = { llvm_dir .. "/bin/liblldb.dll", } end for _, runtime in ipairs(runtimes) do table.insert( commands, '{COPYFILE} "' .. runtime .. '" "%{cfg.targetdir}"' ) end return commands end function setup_target() targetdir("bin/" .. output_dir) objdir("bin-int/" .. output_dir .. "/%{prj.name}") staticruntime "On" filter "system:windows" staticruntime "Off" filter {} end function setup_c_target() setup_target() filter { "system:linux or system:macosx" } buildoptions { "-Wall", "-Wextra", "-Wpedantic", "-Wconversion", "-Wsign-conversion", "-Wshadow", "-Wstrict-prototypes", "-Wmissing-prototypes", } filter {} filter "configurations:debug" runtime "Debug" symbols "On" filter { "system:linux or system:macosx" } buildoptions { "-g", "-fno-omit-frame-pointer", "-fsanitize=address,undefined", } linkoptions { "-fsanitize=address,undefined", } filter {} filter { "configurations:release or configurations:dist" } runtime "Release" optimize "Speed" filter {} filter "configurations:dist" symbols "Off" filter {} end function setup_cpp_target() setup_target() cppdialect "C++23" filter { "system:linux or system:macosx" } buildoptions { "-Wall", "-Wextra", "-Wpedantic", "-Wconversion", "-Wsign-conversion", "-Wshadow", } filter {} filter "configurations:debug" runtime "Debug" symbols "On" filter { "system:linux or system:macosx" } buildoptions { "-g", "-fno-omit-frame-pointer", "-fsanitize=address,undefined", } linkoptions { "-fsanitize=address,undefined", } filter {} filter { "configurations:release or configurations:dist" } runtime "Release" optimize "Speed" filter {} filter "configurations:dist" symbols "Off" filter {} end newaction { trigger = "clean", description = "Remove build output and generated project files", execute = function() os.rmdir("bin") os.rmdir("bin-int") os.rmdir(".vs") os.remove("Makefile") os.remove("imgui.ini") os.remove("compile_commands.json") local patterns = { "*.make", "*.sln", "*.vcxproj", "*.vcxproj.*", } for _, pattern in ipairs(patterns) do for _, file in ipairs(os.matchfiles(pattern)) do os.remove(file) end end print("Cleaned build output and generated project files") end } newaction { trigger = "check", description = "Run static analysis with cppcheck", execute = function() local result = os.execute("make clean") if result ~= true and result ~= 0 then error("Failed to clean project") end result = os.execute("bear -- make config=debug") if result ~= true and result ~= 0 then error("Failed to generate compile_commands.json") end result = os.execute( "cppcheck " .. "--project=compile_commands.json " .. "--file-filter=src/** " .. "--enable=warning,style,performance,portability " .. "--error-exitcode=1" ) if result ~= true and result ~= 0 then error("cppcheck found issues") end end } newaction { trigger = "fetch-llvm", description = "Download the pinned llvm release into " .. llvm_vendored_dir, execute = function() if os.isdir(llvm_vendored_dir .. "/include/lldb") then print( llvm_vendored_dir .. " already has an llvm with lldb headers" ) return end local asset = llvm_release_asset() if asset == nil then error( "no pinned llvm release for " .. os.host() .. " " .. os.hostarch() .. ", install llvm yourself and set LLVM_PREFIX" ) end local archive = "ext/" .. asset local staging = "ext/llvm-staging" if not os.isfile(archive) then local url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-" .. llvm_version .. "/" .. asset print("downloading " .. url) local reported = 0 local result, code = http.download( url, archive, { progress = function(total, current) if total > 0 and current - reported >= total / 20 then reported = current printf( " %d%% (%.0f mb)", math.floor(current / total * 100), current / 1048576 ) end end } ) if result ~= "OK" then os.remove(archive) error( "download failed with " .. tostring(code) .. ": " .. tostring(result) ) end end os.rmdir(staging) os.mkdir(staging) print("extracting " .. asset) local extracted = os.execute( 'tar -xf "' .. archive .. '" -C "' .. staging .. '"' ) if extracted ~= true and extracted ~= 0 then error( "could not extract " .. archive .. ", the system tar may lack xz support, " .. "unpack it into " .. llvm_vendored_dir .. " by hand" ) end local unpacked = os.matchdirs(staging .. "/*")[1] if unpacked == nil then error(archive .. " did not contain an llvm directory") end os.rmdir(llvm_vendored_dir) if not os.rename(unpacked, llvm_vendored_dir) then error( "could not move " .. unpacked .. " to " .. llvm_vendored_dir ) end os.rmdir(staging) os.remove(archive) print( "llvm " .. llvm_version .. " is ready in " .. llvm_vendored_dir ) end } workspace "hsdbg" architecture(host_architecture) startproject "hsdbg" multiprocessorcompile "On" configurations { "debug", "release", "dist", } filter "system:windows" defines "HSDBG_WINDOWS" filter "system:linux" defines "HSDBG_LINUX" filter "system:macosx" defines "HSDBG_MACOS" filter {} group "dependencies" project "glfw" kind "StaticLib" language "C" warnings "Off" setup_c_target() files { "ext/glfw/src/context.c", "ext/glfw/src/init.c", "ext/glfw/src/input.c", "ext/glfw/src/monitor.c", "ext/glfw/src/platform.c", "ext/glfw/src/vulkan.c", "ext/glfw/src/window.c", "ext/glfw/src/internal.h", "ext/glfw/src/platform.h", "ext/glfw/src/mappings.h", "ext/glfw/src/null_init.c", "ext/glfw/src/null_joystick.c", "ext/glfw/src/null_joystick.h", "ext/glfw/src/null_monitor.c", "ext/glfw/src/null_platform.h", "ext/glfw/src/null_window.c", } filter "system:linux" pic "On" defines "_GLFW_X11" files { "ext/glfw/src/x11_init.c", "ext/glfw/src/x11_monitor.c", "ext/glfw/src/x11_platform.h", "ext/glfw/src/x11_window.c", "ext/glfw/src/xkb_unicode.c", "ext/glfw/src/xkb_unicode.h", "ext/glfw/src/wl_init.c", "ext/glfw/src/wl_monitor.c", "ext/glfw/src/wl_platform.h", "ext/glfw/src/wl_window.c", "ext/glfw/src/posix_module.c", "ext/glfw/src/posix_time.c", "ext/glfw/src/posix_time.h", "ext/glfw/src/posix_thread.c", "ext/glfw/src/posix_thread.h", "ext/glfw/src/posix_poll.c", "ext/glfw/src/posix_poll.h", "ext/glfw/src/glx_context.c", "ext/glfw/src/egl_context.c", "ext/glfw/src/osmesa_context.c", "ext/glfw/src/linux_joystick.c", "ext/glfw/src/linux_joystick.h", } filter "system:macosx" pic "On" defines "_GLFW_COCOA" files { "ext/glfw/src/cocoa_init.m", "ext/glfw/src/cocoa_joystick.h", "ext/glfw/src/cocoa_joystick.m", "ext/glfw/src/cocoa_monitor.m", "ext/glfw/src/cocoa_platform.h", "ext/glfw/src/macos_time.c", "ext/glfw/src/macos_time.h", "ext/glfw/src/cocoa_window.m", "ext/glfw/src/nsgl_context.m", "ext/glfw/src/egl_context.c", "ext/glfw/src/osmesa_context.c", "ext/glfw/src/posix_module.c", "ext/glfw/src/posix_thread.c", "ext/glfw/src/posix_thread.h", } filter "system:windows" defines { "_GLFW_WIN32", "_CRT_SECURE_NO_WARNINGS", } files { "ext/glfw/src/win32_init.c", "ext/glfw/src/win32_joystick.c", "ext/glfw/src/win32_joystick.h", "ext/glfw/src/win32_module.c", "ext/glfw/src/win32_monitor.c", "ext/glfw/src/win32_platform.h", "ext/glfw/src/win32_thread.c", "ext/glfw/src/win32_thread.h", "ext/glfw/src/win32_time.c", "ext/glfw/src/win32_time.h", "ext/glfw/src/win32_window.c", "ext/glfw/src/wgl_context.c", "ext/glfw/src/egl_context.c", "ext/glfw/src/osmesa_context.c", } filter {} project "glad" kind "StaticLib" language "C" warnings "Off" setup_c_target() files { "ext/glad/include/**.h", "ext/glad/src/**.c", } includedirs "%{include_dir.glad}" filter { "system:linux or system:macosx" } pic "On" filter {} project "imgui" kind "StaticLib" language "C++" warnings "Off" setup_cpp_target() defines "GLFW_INCLUDE_NONE" files { "ext/imgui/imconfig.h", "ext/imgui/imgui.h", "ext/imgui/imgui.cpp", "ext/imgui/imgui_draw.cpp", "ext/imgui/imgui_internal.h", "ext/imgui/imgui_tables.cpp", "ext/imgui/imgui_widgets.cpp", "ext/imgui/imgui_demo.cpp", "ext/imgui/imstb_rectpack.h", "ext/imgui/imstb_textedit.h", "ext/imgui/imstb_truetype.h", "ext/imgui/misc/cpp/imgui_stdlib.h", "ext/imgui/misc/cpp/imgui_stdlib.cpp", "ext/imgui/backends/imgui_impl_glfw.h", "ext/imgui/backends/imgui_impl_glfw.cpp", "ext/imgui/backends/imgui_impl_opengl3.h", "ext/imgui/backends/imgui_impl_opengl3.cpp", "ext/imgui/backends/imgui_impl_opengl3_loader.h", } includedirs { "%{include_dir.imgui}", "%{include_dir.imgui_backends}", "%{include_dir.glfw}", } filter { "system:linux or system:macosx" } pic "On" filter "system:macosx" defines "GL_SILENCE_DEPRECATION" filter "system:windows" defines "_CRT_SECURE_NO_WARNINGS" filter {} group "" project "hsdbg" kind "ConsoleApp" language "C++" setup_cpp_target() defines { "_CRT_SECURE_NO_WARNINGS", "GLFW_INCLUDE_NONE", } files { "src/**.h", "src/**.cpp", } includedirs { "src", "%{include_dir.glfw}", "%{include_dir.glad}", "%{include_dir.imgui}", "%{include_dir.imgui_backends}", "%{include_dir.lldb}", "ext/stb", } links { "glfw", "glad", "imgui", } defines { "HSDBG_LLVM_PREFIX=\"" .. llvm_dir .. "\"", "HSDBG_ASSET_DIR=\"" .. _MAIN_SCRIPT_DIR .. "/assets\"", } linkoptions { lldb_library(), } filter "system:windows" systemversion "latest" links "opengl32" postbuildcommands(windows_runtime_copies()) filter "system:not windows" linkoptions { "-Wl,-rpath," .. library_dir.lldb, } filter "system:linux" links { "GL", "dl", "m", "pthread", } filter "system:macosx" defines "GL_SILENCE_DEPRECATION" links { "Cocoa.framework", "IOKit.framework", "CoreFoundation.framework", "CoreVideo.framework", "OpenGL.framework", "QuartzCore.framework", } filter "configurations:debug" defines "HSDBG_DEBUG" filter "configurations:release" defines "HSDBG_RELEASE" filter "configurations:dist" defines "HSDBG_DIST" filter {}