adamrehn / conan-ue4cli

Integrate third-party libraries into the Unreal Engine with Conan
https://docs.adamrehn.com/conan-ue4cli/
MIT License
87 stars 20 forks source link

Question: packaging UE plugins as Conan packages? #17

Open jlsalmon opened 2 years ago

jlsalmon commented 2 years ago

Hi @adamrehn and co,

A potentially silly question incoming, but do you think it would theoretically be possible to bundle a regular UE plugin as a Conan package? At my studio we're currently using git submodules to include plugins within projects, and it's always felt uncomfortable to me, since I'm used to having proper dependency management with semantically versioned libraries. Having just started to use conan-ue4cli to package 3rd-party C++ libraries for UE projects, it occurred to me that it would be great if there was a way to use Conan as a dependency manager for UE plugins as well as vanilla C++ libraries.

Of course, since I'm fairly new to the UE world, I could be overlooking some obvious reasons why this might be a terrible idea.

Many thanks in advance!

jlsalmon commented 2 years ago

So I ended up answering my own question: it doesn't seem to be possible to do the necessary wiring from within a boilerplate module, since the project rules assembly will already have been created, and the module rules don't have access to add new ones at runtime.

So, I decided to patch the engine to allow executing scripts at an earlier point in the build lifecycle: https://github.com/EpicGames/UnrealEngine/pull/9272

This works great for my needs, and combined with conan-ue4cli boilerplate modules I have a fully-functioning package management solution for UE 🎉

lvanname commented 2 years ago

Hi, Unfortunately I have been trying to build and package UE plugins as conan packages for the past 6 weeks and have obvioulsy not gotten very far. Just came across this issue and @jlsalmon I read your solution that you attached above.

I was wondering if you thought your solution would also work in my situation?

Currently, I want to build and package a plugin using conan and then I want to push the binaries of that plugin to a package registry for later use. This way, now any UE project can access the plugin binaries for their project, rather than duplicating the source of the plugin.

Thank you!

jlsalmon commented 2 years ago

This is how I build conan packages for UE plugins:

Example conanfile.py:

import os

from conans import ConanFile
from ue4cli import UnrealManagerFactory

class MyPlugin(ConanFile):
    name = "MyPlugin"
    version = "0.0.1"
    settings = "os", "compiler", "build_type", "arch"

    def export_sources(self):
        self.copy("*")

    def build(self):
        if self.settings.os == "Macos":
            platform = "Mac"
        elif self.settings.os == "Windows":
            platform = "Win64"
        else:
            platform = "Linux"

        manager = UnrealManagerFactory.create()
        manager.packageDescriptor(dir=os.getcwd(), args=[f"-TargetPlatforms={platform}"])

    def package(self):
        self.copy("*", src="dist")

Example commands to build and upload the package (I use GitLab's conan package registry support, but any conan-compatible registry should work):

conan remote add my-remote <your_conan_registry_url>
conan create . jlsalmon/4.27 --profile=ue4.27-Win64
conan upload MyPlugin/0.0.1@jlsalmon/4.27 -r my-remote --all

This obviously assumes that you have previously run ue4 conan generate, and you probably also want to upload the conan-ue4cli generated packages to your conan package registry.

Once you've got everything built and uploaded, you can reference your UE plugin from your UE project in conanfile.txt:

[requires]
MyPlugin/0.0.1@jlsalmon/4.27

And in your project's .Build.cs:

public class MyProject : ModuleRules
{
    public MyProject(ReadOnlyTargetRules Target) : base(Target)
    {
        PublicDependencyModuleNames.AddRange(new string[] { "MyPlugin" });
    }
}

Then you can conan install --remote=my-remote these packages to the local package cache on any machine.

Next, you need to somehow get the project to find the pre-built plugin binaries. The way I do this is by putting them in the Intermediate/Source directory, which UBT will search inside for plugins (this directory does not get checked in to source control). The easiest way to do this is to simply copy the packages from the local conan package cache into the project's Intermediate/Source directory. Here's a small Python snippet that does this:

  project_root = "<my_project_root>"
  plugin_root = f"{project_root}/Intermediate/Source"

  shell.exec(f"conan install {project_root} --install-folder={project_root} -g=json --profile=4.27-Win64")

  with open(f"{project_root}/conanbuildinfo.json", "r") as f:
      plugin_info = json.loads(f.read())

  for plugin in plugin_info["dependencies"]:
      src = plugin["rootpath"]
      dest = f"{plugin_root}/{plugin['name']}"
      shutil.copytree(src, dest, dirs_exist_ok=True)

Now you can just use regular ue4 build and everything should work as normal.

The custom Engine patch that I made just adds another layer of automation to this by having UBT invoke a script like the one above during the build process, but you don't necessarily need this. Any pre-build mechanism that ensures the pre-built plugin binaries are copied to Intermediate/Source should work.

Hope this helps!