adamrehn / ue4cli

Command-line interface for Unreal Engine 4
https://docs.adamrehn.com/ue4cli/
MIT License
249 stars 45 forks source link

Feature Request: Build non-project-specific tools with ue4 build #25

Open TBBle opened 3 years ago

TBBle commented 3 years ago

Right now, ue4 build prepends the project name to the provided target.

We have special-case code to build ShaderCompilerWorker (from #14) but no way to do such compilation in general.

In my immediate use-case, I was trying to compile UnrealFrontend.

PS > ue4 build Development UnrealFrontend
Using user-specified engine root: D:\Project
Creating makefile for ProjectUnrealFrontend (no existing makefile)
ERROR: Couldn't find target rules file for target 'ProjectUnrealFrontend' in rules assembly 'UE4Rules, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
       Location: D:\Project\Engine\Intermediate\Build\BuildRules\UE4Rules.dll
       Target rules found:
Traceback (most recent call last):
...
Exception: child process ['D:\\Project\\Engine\\Build\\BatchFiles\\Build.bat', 'ProjectUnrealFrontend', 'Win64', 'Development', '-project=D:\\Project\\project\\Project.uproject'] failed with exit code 5

Taking the command-line that was generated and removing the project name from the target name was sufficient to make this work, e.g.,

D:\\Project\\Engine\\Build\\BatchFiles\\Build.bat UnrealFrontend Win64 Development -project=D:\\Project\\project\\Project.uproject

That would have worked without -project too, I was just looking for the minimal patch. I'm honestly not sure if every Target in a project needs to start with (or equal) the project name, or if that's just convention for the game-variant and editor builds.

Possible UX:

ue4 build Development -istool UnrealFrontend

I'm not sure what the right command-line option would be in this case.

Another option is -noproject (which would also exclude -project from UBT like we do for ShaderCompileWorker now) but that would block targets in the project that do not include the name of the project as a prefix, I think.

It might also be possible to get UE4BuildTool to list the possible targets, and then automatically recognise when a target needs the Project prefix added, in which case -noproject is a better option.

Edit: I was looking at TargetDescriptor.cs, and the way this tool currently takes 'Game', 'Editor', 'Client', 'Server' is actually something we could pass verbatim to -TargetType=, and then the flag for this feature request would be -explicittarget to indicate to pass the given name to -Target, i.e.

# These two build the same thing, from ProjectEditor.Target.cs, which specifies `Type = TargetType.Editor`.
# -TargetType requires a -project
PS> D:\Project\Engine\Build\BatchFiles\Build.bat -TargetType=Editor Win64 Development -project=D:\\Project\\project\\Project.uproject
PS> D:\Project\Engine\Build\BatchFiles\Build.bat -Target=ProjectEditor Win64 Development -project=D:\\Project\\project\\Project.uproject
# This builds shadercompileworker. -project is unnecessary for this particular instance, but you can't tell that without parsing the rules assembly for NativeTargets.
PS> D:\Project\Engine\Build\BatchFiles\Build.bat -Target=ShaderCompileWorker Win64 Development -project=D:\\Project\\project\\Project.uproject

-Target and -TargetType were introduced in UE4.20 though, replacing the existing code which generally concatenated the project name and the target name. So they might not be feasible for ue4cli, depending on how far back it needs to support UE4.

adamrehn commented 3 years ago

I've been hesitant to add this functionality to the ue4 build command because it's explicitly designed to be a descriptor-scope command rather than an engine-scope command, and because such an addition would require the introduction of somewhat awkward syntax to maintain backwards compatibility with existing usage of the command. I agree that this is a valid use case for ue4cli though, so to that end I've added an entirely separate command in commit 3d590b0 (live in ue4cli version 0.0.48) called ue4 build-target that is solely responsible for invoking UBT to build arbitrary targets:

ue4 build-target <TARGET> [CONFIGURATION] [EXTRA UBT ARGS]

With regards to the implementation, I've had to simply call Build.bat/Build.sh without the -project flag, since ue4cli still officially supports Unreal Engine 4.19, which precludes the use of the niceties introduced in newer Engine versions.

Give it a try and let me know if it works nicely for your use case!

adamrehn commented 3 years ago

Just FYI, this command will map to ue engine build in my current proposal for unreal-cli.

TBBle commented 3 years ago

So I've just hit another corner-case related to this request. The UE Shooter Game example includes the following:

Using ue4 build, only "Editor" works, as the others are trying to prepend ShooterGame, but the files are just Shooter. >_< Unlike the original request, these would need the -Project flag.

ue4 build-target ShooterServer Development -project=C:\Path\To\ShooterGame.uproject

works, as you'd expect.

adamrehn commented 3 years ago

Well, that's just plain flying in the face of established conventions. I wonder if that project breaks any of the Unreal Engine's own tooling with that naming scheme. Is UAT even able to package that project correctly if the -noclient -server flags are specified?

TBBle commented 3 years ago

I didn't try, but I strongly suspect more tooling than just ue4cli will barf on that, when it tries to assemble a target name from the project and target type. Unless the UE4 code-base never assumes that can happen, in which case ue4cli has been caught out on a limb. -_-

That said, the 4.26 version of ShooterGame includes a BuildGraph script, so it's possible they are accounting for the names when packaging by explicitly naming targets when necessary; I didn't check that either, since we're not using the 4.26 version yet.

TBBle commented 3 years ago

As a follow-up, ue4 package -client -noserver and ue4 package -noclient -server has no problems with the Shooter Game's target layout. I assume UAT BuildCookRun discovers targets by looking at all *.Target.cs files and selecting those with the matching TargetType value.

I've only tested this on UE 4.26 though (and probably UE 4.24) so perhaps this relies on -TargetType mentioned in the initial request? I haven't checked the resulting UBT command-lines, if they're even visible or even exist. I don't know if UAT is just calling through to UBT directly rather than via command-line, for that matter.

Either way, perhaps ue4 build should work the same way... When the specified target is precisely a non-Program TargetType (literally one of Editor/Game/Client/Server), it should find a target (or targets) in the current project for that type and build them.

That would have the same behaviour as now, unless people have been relying on the prepending to build, e.g. a ProjectClient.Target.cs which is actually 'Game' type; in that case, UAT would probably have done a wrong or surprising thing.

If the target is not a known target type, it should take the target literally, rather than prepending the project name. That would replace ue4 build-target -project=....

ue4 build-target can continue to be used for targets from UE4 itself, as they don't need -project, i.e. the UnrealFrontend use-case for which it was added.

sleeptightAnsiC commented 3 months ago

At this point, pretty much any solution to this would be "ugly". But I think that ue4 build-target could search for .project file in parent directory and implicitly add -project=... flag if said file was found. Though, I'm not fully sure, if this gonna break something in other use cases. Should be pretty easy to implement.