Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduction of the cargo.build rule to manage patternsleuth as a target #516

Merged
merged 6 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 62 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ If you are planning on doing mod development using UE4SS, you can do the same as
- Visual Studio 2019 (recent versions), and Visual Studio 2022 will work.
- More compilers will hopefully be supported in the future.
- Rust toolchain 1.73.0 or greater
- [xmake](https://xmake.io/#/)

- [xmake >= 2.9.2](https://xmake.io/#/)

## Build instructions

Expand All @@ -68,9 +67,18 @@ If you are planning on doing mod development using UE4SS, you can do the same as

There are several different ways you can build UE4SS.

### Building from cli
## Building from cli
narknon marked this conversation as resolved.
Show resolved Hide resolved

### Configuration settings

`xmake` allows you to flexibly configure some build options to suit your specific needs. The following is a non-comprehensive list of configuration settings you might find useful.

> [!IMPORTANT]
> All configuration changes are made by using the `xmake config` command. You can also use `xmake f` as an alias for con**f**ig.

After configuring `xmake` with any of the following options, you can build the project with `xmake` or `xmake build`.

Configure the project using this command: `xmake f -m "<BuildMode>"`
#### Mode

The build modes are structured as follows: `<Target>__<Config>__<Platform>`

Expand All @@ -89,26 +97,70 @@ Currently supported options for these are:
* `Platform`
* `Win64` - 64-bit windows

> [!TIP]
> Configure the project using this command: `xmake f -m "<BuildMode>"`. `-m` is an alias for --**m**ode=\<BuildMode>.

#### Patternsleuth (Experimental)

By default, the patternsleuth tool installs itself as an xmake package. If you do not intend on modifying the patternsleuth source code, then you don't have to configure anything special. If you want to be able to modify the patternsleuth source code, you have to supply the `--patternsleuth=local` option to `xmake config` in order to recompile patternsleuth as part of the UE4SS build.

#### Proxy Path

By default, UE4SS generates a proxy based on `C:\Windows\System32\dwmapi.dll`. If you want to change this for any reason, you can supply the `--ue4ssProxyPath=<path proxy dll>` to the `xmake config` command..

#### Profiler Flavor

Now to build it, just run `xmake`
By default, UE4SS uses Tracy for profiling. You can pass `--profilerFlavor=<profiler>` to the `xmake config` command to set the profiler flavor. The currently supported flavors are `Tracy`, `Superluminal`, and `None`.

### Helpful `xmake` commands

You may encounter use for the some of the more advanced `xmake` commands. A non-comprehensive list of some useful commands is included below.

| Syntax | Aliases | Uses |
| --- | --- | --- |
| `xmake <command> --yes` | `xmake <command> -y` | Automatically confirm any user prompts. |
| `xmake --verbose <command>` | `xmake -v <command>` | Enable verbose level logging. |
| `xmake --Diagnostic <command>` | `xmake -D <command>` | Enable diagnostic level logging. |
| `xmake --verbose --Diagnostic --yes <command>` | `xmake -vDy <command>` | You can combine most flags into a single `-flagCombo`. |
| `xmake config` | `xmake f` | Configure xmake with any of [these options](#configuration-settings). |
| `xmake clean --all` | `xmake c --all` | Cleans binaries and intermediate output of all targets. |
| `xmake clean <target>` | `xmake c <target>` | Cleans binaries and intermediates of a specific target. |
| `xmake build` | `xmake b` | Incrementally builds UE4SS using input file detection. |
| `xmake build --rebuild` | `xmake b -r` | Forces a full rebuild of UE4SS. |
| `xmake build <target>` | `xmake b <target>` | Incrementally builds a specific target. |
| `xmake show` | | Shows xmake info and current project info. |
| `xmake show --target=<target>` | `xmake show -t <target>` | Prints lots of information about a target. Useful for debugging scripts, compiler flags, dependency tree, etc. |
| `xmake require --clean` | `xmake q -c` | Clears all package caches and uninstalls all not-referenced packages. |
| `xmake require --force` | `xmake q -f` | Force re-installs all dependency packages. |
| `xmake require --list` | `xmake q -l` | Lists all packages that are needed for the project. |
| `xmake project --kind=vsxmake2022 --modes="Game__Shipping__Win64"` | `xmake project -k vsxmake2022 -m "Game__Shipping__Win64"` | Generates a [Visual Studio project](#visual-studio--rider) based on your current `xmake config`uration. You can specify multiple modes to generate by supplying `-m "Comma,Separated,Modes"`. If you do not supply any modes, the VS project will generate all [permutations of modes](#mode). |

### Opening in an IDE

#### Visual Studio / Rider

To generate Visual Studio project files, run the `xmake project -k vsxmake2022` command.
To generate Visual Studio project files, run the `xmake project -k vsxmake2022 -m "Game__Shipping__Win64"` command.

Afterwards open the generated `.sln` file inside of the `vsxmake2022` directory

Note that you should also commit & push the submodules that you've updated if the reason why you updated was not because someone else pushed an update, and you're just catching up to it.

**Note the following about how xmake interacts with VS**

> [!WARNING]
> The vs. build plugin performs the compile operation by directly calling the xmake command under vs, and also supports intellisense and definition jumps, as well as breakpoint debugging.

This means that modifying the project properties within Visual Studio will not affect which flags are passed to the build when VS executes `xmake`. XMake provides some configurable project settings
> This means that modifying the project properties within Visual Studio will not affect which flags are passed to the build when VS executes `xmake`. XMake provides some configurable project settings
which can be found in VS under the `Project Properties -> Configuration Properties -> Xmake` menu.

##### Configuring additional modes

> [!TIP]
> Additional modes can be generated by running `xmake project -k vsxmake2022 -m "Game__Shipping__Win64,Game__Debug__Win64"`.
> [Further explanation can be found in the `xmake` command table](#helpful-xmake-commands).

##### Regenerating solution best practices

> [!CAUTION]
> If you change your configuration with `xmake config`, you *may* need to regenerate your Visual Studio solution to pick up on changes to your configuration. You can simply re-run the `xmake project -k vsxmake2022 -m "<modes>"` command to regenerate the solution.

## Updating git submodules

If you want to update git submodules, you do so one of three ways:
Expand Down
2 changes: 1 addition & 1 deletion deps/first/patternsleuth_bind/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion deps/first/patternsleuth_bind/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2021"

[dependencies]
patternsleuth = { path = "../patternsleuth/patternsleuth", features = ["process-internal"] }
patternsleuth = { path = "../patternsleuth/patternsleuth", features = ["process-internal"] }
27 changes: 27 additions & 0 deletions deps/first/patternsleuth_bind/xmake.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-- If patternsleuth is configured to install as a package.
add_requires("cargo::patternsleuth_bind", { optional = not is_config("patternsleuth", "package"), debug = is_mode_debug(), configs = { cargo_toml = path.join(os.scriptdir(), "Cargo.toml") } })

target("patternsleuth_bind")
set_kind("static")
set_values("rust.cratetype", "staticlib")
add_files("src/lib.rs")
-- Exposes the src/lib.rs files to the Visual Studio project filters.
add_extrafiles("src/lib.rs")

-- If patternsleuth is configured to install as a package.
if is_config("patternsleuth", "package") then
add_packages("cargo::patternsleuth_bind")
add_links("ws2_32", "advapi32", "userenv", "ntdll", "oleaut32", "bcrypt", "ole32", { public = true })
end

-- If patternsleuth should be built as part of compilation.
if is_config("patternsleuth", "local") then
add_deps("patternsleuth")
add_rules("rust.link")
end

-- We need to clean up the non-selected package/local version of patternsleuth when we reconfigure.
-- This just deletes the .lib and keeps cargo deps on disk for faster recompilation.
on_config(function(target)
os.tryrm(target:targetfile())
end)
32 changes: 20 additions & 12 deletions deps/first/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,29 @@ includes("LuaMadeSimple")
includes("LuaRaw")
includes("MProgram")
includes("ParserBase")
includes("patternsleuth_bind")
includes("Profiler")
includes("ScopedTimer")
includes("SinglePassSigScanner")
includes("Unreal")

-- Patternsleuth -> START
if is_config("patternsleuth", "local") then
-- The patternsleuth target is managed by the cargo.build rule.
target("patternsleuth")
set_kind("static")
add_rules("cargo.build", {project_name = "patternsleuth", is_debug = is_mode_debug(), features= { "process-internal" }})
add_files("patternsleuth/Cargo.toml")
-- Exposes the rust *.rs files to the Visual Studio project filters.
add_extrafiles("patternsleuth/**.rs")
end

add_requires("cargo::patternsleuth_bind", { debug = is_mode_debug(), configs = { cargo_toml = path.join(os.scriptdir(), "patternsleuth_bind/Cargo.toml") } })

target("patternsleuth_bind")
set_kind("static")
set_values("rust.cratetype", "staticlib")
add_files("patternsleuth_bind/src/lib.rs")
add_packages("cargo::patternsleuth_bind")

add_links("ws2_32", "advapi32", "userenv", "ntdll", "oleaut32", "bcrypt", "ole32", { public = true })

-- Patternsleuth -> END
-- This option allows users to choose if patternsleuth should be installed as a package
-- or if patternsleuth should be built as a dependency by xmake. The `package` option
-- should be used if you don't intend on ever modifying the patternsleuth source.
-- The `local` option should be used if you want changes in the patternsleuth
-- submodule to be included as part of the UE4SS build.
option("patternsleuth")
set_default("package")
set_showmenu(true)
set_values("package", "local")
set_description("Install patternsleuth as a package or build it as a dependency.", "package", "local")
63 changes: 63 additions & 0 deletions tools/xmakescripts/modules/cargo/cargo_helpers.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---@alias rust_mode "dev" | "release"

--- Takes a target and returns context variables to be used in on_xxx overrides.
---@param target any xmake target
---@param is_debug boolean Should we get the debug or release context?
---@return string cargo_dir The root cargo dir for the project. Ex. Intermediates/Cargo/target/
---@return string cargo_mode_dir The cargo dir for the debug/release config. Ex. Intermediates/Cargo/target/debug/
---@return rust_mode rust_mode The rust flavor of mode derrived from is_debug param.
function get_cargo_context(target, is_debug)
local rust_mode = is_debug and "dev" or "release"
local rust_mode_dir = is_debug and "debug" or "release"
local cargo_dir = path.join(get_config("buildir"), "cargo", target:name())
return cargo_dir, path.join(cargo_dir, rust_mode_dir), rust_mode
end

--- Parses ".d" files created by Cargo.
---@param file string Path to a ".d" file created by Cargo
---@return string[] cargo_deps A list of any src files that should trigger a rebuild.
function get_dependencies(file)
if not os.exists(file) then
return {}
end

local data = io.readfile(file)
data = data:trim()
local start = data:find(": ", 1, false)
local deps = data:sub(start + 2):split(" ", {strict = false, plain = true})

local parsed_deps = {}
local dep = ""
local dep_idx = 1
while dep do
dep = deps[dep_idx]
if dep then
while dep:endswith("\\") do
dep_idx = dep_idx + 1
dep = dep:sub(1, -2) .. " " .. deps[dep_idx]
end
table.insert(parsed_deps, dep)
dep_idx = dep_idx + 1
end
end

return parsed_deps
end

--[[
The previous function is based on the cargo impl of internal .d parsing.

let mut deps = line[pos + 2..].split_whitespace();

while let Some(s) = deps.next() {
let mut file = s.to_string();
while file.ends_with('\\') {
file.pop();
file.push(' ');
file.push_str(deps.next().ok_or_else(|| {
internal("malformed dep-info format, trailing \\".to_string())
})?);
}
ret.files.push(file.into());
}
]]--
Loading