Skip to content
This repository has been archived by the owner on Jul 1, 2020. It is now read-only.

Compiling on linux for Windows/MacOS/Linux? #4

Open
furai opened this issue Jul 17, 2019 · 17 comments
Open

Compiling on linux for Windows/MacOS/Linux? #4

furai opened this issue Jul 17, 2019 · 17 comments

Comments

@furai
Copy link

furai commented Jul 17, 2019

Hey!

I'm right now stuck with trying to compile SelfPatcher on Linux (Ubuntu 19.04). Is this even possible?

Can I compile it using RIDs so the resulting executables/libraries are working on different platforms like Windows/MacOS/Linux?

I've been trying just to compile the Console App under linux and i can't seem to be able to make it work.

I'm sorry but I'm really new to the topic and I'm not sure if I'm even trying to do the right thing.

EDIT: This was intended to be used later on by my colleague in his Unity game project. If someone was able to just provide me with compiled versions of the latest Patcher version for each platform respectively (MacOS/Linux/Windows) then that would help a lot.

Any instructions and help are highly welcome!

Cheers,
Furai

@yasirkula
Copy link
Owner

You can use .NET Core with Visual Studio to build the SelfPatcherConsoleApp and SimplePatchToolConsoleApp projects. With Mono, you should be able to compile the SelfPatcherWinForms project, as well. But you'll have to generate the MacOS executables on a MacOS and Linux executables on a Linux.

It is also possible to create your own self patcher executable in e.g. Objective-C or C/C++. You can do so by examining SelfPatcher.cs and translating it to the language of your choice.

P.S. If you'd like to create a fresh new .NET Core project and use it to compile SelfPatcherConsoleApp, you just need to copy these 3 C# files to your project and then build the project:

@furai
Copy link
Author

furai commented Jul 17, 2019

So just these 3 files are enough to compile actual SelfPatcher.exe? Does it depend on any specific .NET framework? Or then it's just up to me? That might work for creating solution that is working anywhere dotnet is installed.

I tried using dotnet build but all the time I was getting errors about missing framework. Maybe I was doing something terribly wrong.

Rewriting it in some other language seems kind of promising, there's not that much logic I guess. Would be nice to see a SelfPatcher that works/compiles on any platform.

@yasirkula
Copy link
Owner

Yes, once you build a SelfPatcher with these three .cs files using .NET Core, it is supposed to work on devices with .NET Core Runtime installed. That's the thing about cross-platform C# development: your target platform needs to have certain components installed in order to run the application. But since SimplePatchTool itself is written in C#, the app that integrates SimplePatchTool will also depend on these components to work so if the app can work on a particular OS, so should the self patcher be.

I'm not sure whether or not these components come pre-installed in MacOS or popular Linux distributions because I haven't tested SimplePatchTool on these platforms myself. You can google "net core mac prerequisites" or "mono mac os prerequisites" to learn more.

@furai
Copy link
Author

furai commented Jul 17, 2019

dotnet msbuild -t:Publish -p:RuntimeIdentifiers=osx.10.11-x64
This example command seems promising, I hope this works. I'm really looking into compiling from Linux to different runtimes.
When using mono-xbuild I was running into issue with missing Cryptography.xml which I think I should be able to fix once I figure out how nuget works on linux. But in general it might work there. Used something like:
xbuild /p:Configuration="Release" /p:TargetFrameworkVersion="v.4.5"

I'm sorry for troubling you with all of this. I'm just trying to understand how this things work so we can use Patcher on other platforms than Windows which seems possible but I'm just missing few steps.

@yasirkula
Copy link
Owner

Of course! I'm very interested in seeing the results of your attempts so please keep me updated!

@furai
Copy link
Author

furai commented Jul 17, 2019

Will do. One question - what this Cryptography.XML is used for? Is it something used to securely send files over the net? Or nothing like that?

@yasirkula
Copy link
Owner

It is used in the optional SimplePatchToolSecurity module to sign&verify XML files for increased security against man-in-the-middle attacks: https://github.com/yasirkula/SimplePatchTool/blob/master/SimplePatchToolSecurity/XMLSigner.cs

It requires this NuGet package for .NET Standard 2.0 compatibility: https://www.nuget.org/packages/System.Security.Cryptography.Xml/

@furai
Copy link
Author

furai commented Jul 17, 2019

Ok, I'd like to have that working as well if possible. I guess I'll have to analyse the structure in depth to understand what is what.

@yasirkula
Copy link
Owner

You don't need to know most of the classes, actually. I'd recommend you to follow the instructions on the Wiki, the important classes are already described in detail there: https://github.com/yasirkula/SimplePatchTool/wiki

@furai
Copy link
Author

furai commented Jul 23, 2019

Some progress update - I've decided to just use the project as is and use mono to compile it on Linux/MacOS. It was fairly straightforward.
Only things that were a problem were the PostBuild actions that copied files into right folders - I had to replace copy /Y with cp.
Other than that System.XML had to be changed to System.Xml as Unix systems are case-sensitive.

And now a question - how would you approach creating update tree if our App had release and test configurations?

I was thinking of something like: /PatcherRoot/{test,release}/{Windows,Linux,OSX}/Version/<x.x.x>
Patcher.exe would reside in PatrherRoot and Windows/Linux/OSX are the ProjectRoots (they would hold correct Setting.xml files generated programmatically.

I wonder if this could overwrite in any way the Output folder and render it useless. I guess I won't know until I find out. Unless there is a way to specify Output folder location and I just missed it.

@yasirkula
Copy link
Owner

yasirkula commented Jul 24, 2019

It is possible to completely customize the patch creation process using the legacy method while creating patches. However, I think it would be unnecessary:

I'm assuming the Windows/Linux/OSX folders are SimplePatchTool-projects and Version is actually Versions. Then, you can copy each platform's Patcher.exe to its SelfPatcher directory (e.g. Linux/SelfPatcher/SelfPatcher.exe). Each platform's patch files will be generated inside its own Output directory (e.g. OSX/Output). You can use the Scripting API to create projects or generate patches via these projects.

P.S. While using projects, you can use the PatchUtils.GetProjectInfoFromPath function to deserialize Settings.xml into ProjectInfo, make any changes to that object and then reserialize it to the same path via PatchUtils.SerializeProjectInfoToXML.

P.P.S. While searching for System.XML in SimplePatchTool, I could find only System.Xml. Can you remember which System.XML's you've fixed?

@furai
Copy link
Author

furai commented Jul 27, 2019

diff --git a/SimplePatchToolCore/SimplePatchToolCore.csproj b/SimplePatchToolCore/SimplePatchToolCore.csproj
index fa4bf76..775730b 100644
--- a/SimplePatchToolCore/SimplePatchToolCore.csproj
+++ b/SimplePatchToolCore/SimplePatchToolCore.csproj
@@ -54,7 +54,7 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
-    <Reference Include="System.XML" />
+    <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="External\SharpZipLib\Core\Exceptions\SharpZipBaseException.cs" />
diff --git a/SimplePatchToolSecurity/SimplePatchToolSecurity.csproj b/SimplePatchToolSecurity/SimplePatchToolSecurity.cspr
oj
index b3c8e74..199ace2 100644
--- a/SimplePatchToolSecurity/SimplePatchToolSecurity.csproj
+++ b/SimplePatchToolSecurity/SimplePatchToolSecurity.csproj
@@ -37,10 +37,10 @@
   </ItemGroup>
   <ItemGroup>
     <Reference Include="System.Security" />
-    <Reference Include="System.XML" />
+    <Reference Include="System.Xml" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>

The above are the 2 places (click on them to expand) where I found XML instead of Xml and were giving me issues.

Also thanks for all the help, I've been able to figure it out. Next thing left is testing on these platforms if things actually work.

@jmvogt
Copy link

jmvogt commented Sep 21, 2019

Trying to do something similar here, but I'm looking to use the Unity simple patch tool to make building for Windows, Linux, and MacOS a breeze (rather than building a Windows form using Mono). That and I already have CICD/Jenkins scripts around building multi targeted Unity applications.

At first I converted all of the libraries to .NET standard and all of the console apps to .NET Core. However, to use .NET standard in Unity I had to copy over a lot more dependencies into my Unity project.
image

Then I created a side project to build the SimplePatchToolCore library in .NET Framework so that I wouldn't have to bundle all of those .NET standard DLLs.

Finally, I familiarized myself with Multi Targeted builds from a single project (something I had never done before) and updated ALL libraries to build DLLs for the following targets:

  • .NET Framework 3.5 (to leave the original functionality intact)
  • .NET Framework 4.6.1 (what all of my other, personal, Unity DLLs are targeted with)
  • .NET Standard 2.0 (a common library that could be used by .NET framework or .NET core applications)
  • .NET Core 2.1 (this might not be needed, but it made it easier to generically reference the correct target DLL in the .NET Core console apps)

And updated ALL console apps to build executables for the following targets:

  • .NET Framework 3.5
  • .NET Framework 4.6.1
  • .NET Core 2.1

Note that I left the WinForm projects pointing to .NET Framework 3.5 for now. Once .NET Core 3.0 comes out, I plan on updating the Form projects to build all 3 targets as well.

One thing that was cool.. I was able to get the SelfPatcher to work on MacOS after some minor tweaks to how you're launching the SelfPatcher console app (given that you need to use dotnet to execute a .NET Core Console DLL). One caveat.. files in the wrong subdirectory were being replaced for the Unity application -- but at this point I realized that I could clean this up and contribute a change.

My next steps are to bake the few differences for Unix based systems vs Windows sytems directly into the CSProjs directly using #if NETCORE / OSPlatform.OSX/OSPlatform.Linux runtime checks. Then, I want to make the .NET Console Applications self contained so that they include a local version of dotnet. That way, folks who use the MacOS client don't need to install dotnet just to execute the SelfPatcher console app.

I got a bit giddy when I saw that .NET Core 3 will support Windows Forms, but it looks like they won't be cross platform :(

Note that you can find my changes here:
master...jmvogt:multi_targeted_support

I'm working on the Unix support now -- but if you're interested I'd love to submit a PR against your repo once I'm done. If we move some of wiki docs directly to the README I could then update the instructions on how to build a patch, create a project, etc. for .NET Core. This would help keep the instructions versioned with changes to the repository itself. Not a big deal -- just something to consider for contributions.

@jmvogt
Copy link

jmvogt commented Sep 21, 2019

Just realized that furai is trying to compile on Linux. I guess this is quite a bit different since I'm more trying to build a cross-platform Unity patcher on Windows.

I assume this might still make the process of getting a Linux build server up quicker as most pieces are being built in .NET standard/.NET core with my changes. I've never tried to open up a visual studio SLN in MacOS or Linux so I'm really not sure if they'll freak out from having .NET 3.5/4.6.1 targets -- or if they will just skip those and build the .NET Standard / .NET Core libraries/console apps.

@jmvogt
Copy link

jmvogt commented Sep 21, 2019

So I was able to get a self-contained SelfPatcher created using the dotnet publish command with a specific runtime:

dotnet publish -c debug -r osx-x64 -f netcoreapp2.1

To get around the Unity subdirectory issue (for macos the directory for the self patcher will launch in .app/Contents/MacOs where it needs to launch in .app/) I had to make this modification:
https://github.com/jmvogt/SimplePatchTool/blob/b9c98fab3903ba0934c6a7414fadc8cac054c3c4/SimplePatchToolCore/Utilities/PatchUtils.cs#L461-L466

Which then allowed me to add this in the Unity MultiGame demo script:

            launcherDirectory = Path.GetDirectoryName(PatchUtils.GetCurrentExecutablePath());

#if UNITY_STANDALONE_OSX
            launcherDirectory += "/../..";
#endif

            gamesDirectory = Path.Combine(launcherDirectory, gamesSubdirectory);
            selfPatcherPath = PatchUtils.GetDefaultSelfPatcherExecutablePath(launcherDirectory, selfPatcherExecutable);

The only problem I'm having now.. after the SelfPatcher is downloaded for the first time I will always need to chmod +x the Unity launcher/SelfPatcher console app before restarting/applying the Launcher patch.

If you guys have any ideas on how to make sure the downloaded file can be executed on a Unix based system.. let me know. Seems to be the last piece for me to have this all working cross-platform.

@jmvogt
Copy link

jmvogt commented Sep 21, 2019

Well, not sure whats causing the issue.. but I was able to add a workaround in the Unity client:

#if (UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX)
                    var escapedArgs = $"chmod +x \\\"{selfPatcherPath}\\\"";

                    var process = new Process() {
                        StartInfo = new ProcessStartInfo {
                            FileName = "/bin/bash",
                            Arguments = $"-c \"{escapedArgs}\"",
                            RedirectStandardOutput = true,
                            UseShellExecute = false,
                            CreateNoWindow = true,
                        }
                    };
                    process.Start();
                    process.StandardOutput.ReadToEnd();
                    process.WaitForExit();
#endif

@furai
Copy link
Author

furai commented Sep 21, 2019

The permissions problem is due to the fact that you probably ship it from Windows. Windows has different permission system than Linux and it's really hard to work around that. Best is to apply fix permissions in CD after you upload the file to Linux host.

As to my original issue - I've managed to build it on each platform (Linux/MacOS/Windows respectively) using mono 6.0 and msbuild.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants