diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..5fd48ca6 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,104 @@ +name: Build + +on: + push: + branches: [master, develop] + tags: ["v*.*.*"] + pull_request: + paths-ignore: ["**/*.md", "doc/**"] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install premake5 + run: | + winget install -e --id Premake.Premake.5.Beta --accept-source-agreements --accept-package-agreements --disable-interactivity + $env:Path = [System.Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path','User') + echo "$((Get-Command premake5).Path | Split-Path -Parent)" >> $env:GITHUB_PATH + + - name: Install v141_xp toolset + shell: cmd + run: | + "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\setup.exe" modify ^ + --passive --norestart ^ + --installPath "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" ^ + --add Microsoft.VisualStudio.Component.VC.v141.x86.x64 ^ + --add Microsoft.VisualStudio.Component.WinXP + + - uses: microsoft/setup-msbuild@v2 + + - name: Add pdbcopy to PATH + run: echo "${env:ProgramFiles(x86)}\Windows Kits\10\Debuggers\x86" >> $env:GITHUB_PATH + + - name: Build + env: + CL: /MP + run: | + if ("${{ github.ref }}" -like "refs/tags/v*") { + premake5 --file=release.lua prepare --toolset=vs2022 --final-release + } else { + premake5 --file=release.lua prepare --toolset=vs2022 + } + + - uses: actions/upload-artifact@v4 + with: + name: modloader-${{ github.sha }} + path: release + include-hidden-files: true + if-no-files-found: error + retention-days: 30 + + release: + if: startsWith(github.ref, 'refs/tags/v') + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: modloader-${{ github.sha }} + path: dist/ + + - name: Package zip files + run: | + (cd dist/binaries && zip -r ../modloader.zip .) + (cd dist/symbols && zip -r ../pdb-symbols.zip .) + + - name: Prepare release notes + env: + TAG: ${{ github.ref_name }} + run: | + python3 <<'PY' + import os, re, sys + tag = os.environ["TAG"] + lines = open("doc/CHANGELOG.md").readlines() + i = next((i for i, l in enumerate(lines) if l.startswith(tag + " ")), None) + if i is None: + sys.exit(f"No changelog for {tag} in CHANGELOG.md") + j = next((j for j in range(i + 1, len(lines)) if re.match(r"^v\d+\.\d+", lines[j])), len(lines)) + open("release-body.md", "w").writelines(lines[i:j]) + PY + + - uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + name: Mod Loader ${{ github.ref_name }} + body_path: release-body.md + files: | + dist/modloader.zip + dist/pdb-symbols.zip + fail_on_unmatched_files: true diff --git a/include/modloader/modloader.h b/include/modloader/modloader.h index 9a63fc5f..5c34980f 100644 --- a/include/modloader/modloader.h +++ b/include/modloader/modloader.h @@ -30,8 +30,8 @@ extern "C" { #define MODLOADER_VERSION_MAJOR 0 #define MODLOADER_VERSION_MINOR 3 #define MODLOADER_VERSION_REVISION 9 -#ifdef NDEBUG -#define MODLOADER_VERSION_ISDEV 1 +#ifdef MODLOADER_FINAL_RELEASE +#define MODLOADER_VERSION_ISDEV 0 #else #define MODLOADER_VERSION_ISDEV 1 #endif diff --git a/premake5.lua b/premake5.lua index ad102dbe..b0571152 100644 --- a/premake5.lua +++ b/premake5.lua @@ -24,6 +24,11 @@ newoption { description = "Post-build install directory" } +newoption { + trigger = "final-release", + description = "Public release build (defines MODLOADER_FINAL_RELEASE for the whole solution)" +} + newaction { trigger = "clean", description = "Cleans the binary and build files on the directory (bin/, build_temp/)", @@ -204,6 +209,10 @@ solution "modloader" "_SCL_SECURE_NO_WARNINGS" } + if _OPTIONS["final-release"] then + defines { "MODLOADER_FINAL_RELEASE" } + end + includedirs { "include", "deps/cereal/include", diff --git a/release.bat b/release.bat index 9c345190..3a994b31 100644 --- a/release.bat +++ b/release.bat @@ -1,5 +1,11 @@ @echo off +echo Are you sure this is a final release? +echo This will not be tagged in the logs as a development build. +choice /C YN /M "Continue" +if errorlevel 2 exit /b 1 + set CL=/MP -premake5 --file=release.lua prepare --toolset=vs2015 -pause -goto:eof +set "PATH=%ProgramFiles(x86)%\Windows Kits\10\Debuggers\x86;%PATH%" +premake5 --file=release.lua prepare --toolset=vs2022 --final-release + +pause \ No newline at end of file diff --git a/release.lua b/release.lua index bf9849e0..7a0d5b8c 100644 --- a/release.lua +++ b/release.lua @@ -10,67 +10,64 @@ newaction { execute = function() main() end } -newoption { - trigger = "debug-symbols", - description = "Makes a release which contains public debug symbols, which allows better user debugging", -} - newoption { trigger = "toolset", value = "tools", - description = "The toolset used to compile the release build", - allowed = { - { "vs2013", "Microsoft Visual Studio 2013" }, - { "vs2015", "Microsoft Visual Studio 2015" }, - { "gcc", "GNU Compiler Collection" } - } + description = "The toolset used to compile the release build (vs20xx or gcc)", } +newoption { + trigger = "final-release", + description = "Public release build." +} toolset = _OPTIONS["toolset"] +final_flag = _OPTIONS["final-release"] and " --final-release" or "" action = (toolset == "gcc" and "gmake" or toolset) compiler = (toolset == "gcc" and "gcc" or "cl") build = (toolset == "gcc" and "make" or "msbuild") function main() - local debugsymbols = _OPTIONS["debug-symbols"] - if not toolset then print("No toolset defined.\nAborting.") exit() end + if toolset ~= "gcc" and not toolset:match("^vs") then + print("Unsupported toolset '" .. toolset .. "' (use a vs* premake action or gcc).\nAborting.") + exit() + end + + require_tools() + local install = function() print "Making release directory tree..." - execute("premake5 install ./release/") - os.copyfile("./release/modloader/.data/Readme.md", "./release/Readme.txt") - os.copyfile("./release/modloader/.data/Leia-me.md", "./release/Leia-me.txt") - os.mkdir("./release/modloader/.profiles") + execute("premake5 install ./release/binaries/") + os.copyfile("./release/binaries/modloader/.data/Readme.md", "./release/binaries/Readme.txt") + os.copyfile("./release/binaries/modloader/.data/Leia-me.md", "./release/binaries/Leia-me.txt") + os.mkdir("./release/binaries/modloader/.profiles") end print "Cleaning workspace..." execute("premake5 clean") print "Generating build files..." - if toolset == "gmake" then - execute(string.format("premake5 %s --cc=%s --outdir=build_temp", action, compiler)) + if toolset == "gcc" then + execute(string.format("premake5 %s --cc=%s --outdir=build_temp%s", action, compiler, final_flag)) else - execute(string.format("premake5 %s --outdir=build_temp", action)) + execute(string.format("premake5 %s --outdir=build_temp%s", action, final_flag)) end print "Building..." if build == "msbuild" then - + -- also use 'set CL=/MP' at release.bat execute("msbuild build_temp/modloader.sln /p:configuration=Release /p:platform=Win32 /m") - -- Install THEN move pdbs install() - if debugsymbols then - pdbmove() - end - + pdbpackage() + elseif compiler == "gcc" then local cwd = os.getcwd() @@ -81,9 +78,9 @@ function main() -- Strip binaries (ALWAYS) gccstrip() -- striping is not related to symbols, to have symbols send --export-all-symbols to the linker - + install() - + else print("Internal error") exit() @@ -92,22 +89,21 @@ function main() os.rmdir("build_temp") end +function pdbpackage() + print("Packaging stripped debug symbols (release/symbols/)...") + os.mkdir("release/symbols") + os.mkdir("release/symbols/modloader/.data/plugins/gta3") + execute('pdbcopy "bin/modloader.pdb" "release/symbols/modloader.pdb" -p') -function pdbmove() - print("Moving PDB files into release...") - pdbcopy("bin", "release", false) - pdbcopy("bin/plugins", "release/modloader/.data/plugins", true) -end - -function pdbcopy(src, dest, recursive) - local cwd = os.getcwd() - os.chdir(src) - for i, file in ipairs(os.matchfiles(recursive and "**.pdb" or "*.pdb")) do - execute(string.format([[pdbcopy "%s" "%s" -p]], file, cwd .. '/' .. dest .. '/' .. file)) + for i, file in ipairs(os.matchfiles("bin/plugins/gta3/*.pdb")) do + local name = path.getname(file) + execute(string.format( + 'pdbcopy "bin/plugins/gta3/%s" "release/symbols/modloader/.data/plugins/gta3/%s" -p', + name, name + )) end - os.chdir(cwd) end function gccstrip() @@ -124,16 +120,45 @@ function gccstrip() os.chdir(cwd) end +function require_tools() + require_on_path("premake5", + "Install Premake 5 and add it to PATH.") + if build == "msbuild" then + require_on_path("msbuild", + "Install Visual Studio with MSBuild, then run this from the x86 Native Tools Command Prompt.") + require_on_path("pdbcopy", + "Install the Debugging Tools for Windows component from the Windows SDK," .. + " then add %ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x86 to PATH.") + elseif compiler == "gcc" then + require_on_path("mingw32-make", + "Install MinGW and add mingw32-make to PATH.") + end +end - +function require_on_path(name, hint) + if not os.ishost("windows") then + return + end + local found = os.outputof("where " .. name .. " 2>nul") + if not found or found == "" then + print("Error: " .. name .. " is not on PATH.") + if hint then + print(hint) + end + exit() + end +end function execute(command) - os.execute(command) + local result = os.execute(command) + if result == 0 or result == true then + return + end + print("Command failed: " .. command .. "\nAborting.") + exit() end function exit() os.exit() end - -