premake / premake-core

Premake
https://premake.github.io/
BSD 3-Clause "New" or "Revised" License
3.22k stars 619 forks source link

Add Git Repo Support #1347

Open MaxKruse opened 5 years ago

MaxKruse commented 5 years ago

What problem will this solve? Using git submodules using premake can be somewhat of a pain in the ass: you have to (potentially) fork the repo, make your premake5.lua file, push, and keep your submodule updated manually. Making it easy, similar to how CMake handles git submodule adding, would highly increase the versability of premake. This should use some internal premake caching and not go through .gitsubmodules, as that is a huge pain in the bum to edit your submodules.

What might be a solution? Add a new identifier, called gitsource or similar. This should prompt premake to download from said source, if possible, and all commands and identifiers will be targeted at the downloaded git repo's path, possibly ./dependencies/<Name>.

What other alternatives have you already considered? Using pre-build commands would probably work, but requires a huge amount of work for the enduser to safely use on every platform, or even use subsequently.

Anything else we should know? Here is how I would roughly sketch it currently:

-- premake5.lua
workspace "HelloWorld"
   configurations { "Debug", "Release" }

project "HelloWorld"
   kind "ConsoleApp"
   language "C++"
   targetdir "bin/%{cfg.buildcfg}"

   files { "**.h", "**.cpp" }

   links { "ExampleLibFromGit" }

project "ExampleLibFromGit"
   kind "SharedLib"
   gitsource "https://github.com/exampleUser/exampleLib"
   gitbranch "a-new-branch"
   githash "9a034128a329f4fb7a53043dd1c1e8f74bfc91fc"
   language "C++"
   targetdir "lib/%{cfg.buildcfg}"

   files { "**.h", "**.cpp" }

Proposed commands

ratzlaff commented 5 years ago

If I understand what you are proposing here:

When I update the repo at https://github.com/exampleUser/exampleLib and want this script to use it, I have to change my premake5.lua and update the githash line?

MaxKruse commented 5 years ago

The hash can be used to force use of a single commit in the exampleLib, but it could be optional to always ensure a most up-to-date version will be used. See githash as a way of pinning to a specific commit on a specific branch.

/edit: Edited proposal to be more specific

starkos commented 5 years ago

I was a bit confused by this at first: this actually has nothing to do with Git submodules, but is rather intended to be used as a replacement for them. Yes, Git submodules are a PITA and it would be nice if Premake could help avoid them.

This should use some internal premake caching

I'm unclear on what would need to be cached, exactly?

MaxKruse commented 5 years ago

Do you really need both gitbranch() and githash()? What about a single gitref() that could be either a ref name or a commit hash?

yes of course gitref could also work. My initial thought was to make it very granular to not force one behaviour on the user later on.

Will probably need a gitdir() or the like to specify the location where the working copy should be placed (defaulting to prj.location if not set?)

Possible default to {prj.location}/dependencies/{GitRepoName} as this is plenty verbose. Adding a gitdir would also be a good addition, although adding unneeded complexity to the final product in my eyes.

Would it be okay to require the Git command line tools instead of having to embed Git into Premake? (Thinking mostly so we wouldn't have to version chase Git.)

Requirering git for these actions should be fine, if somebody doesnt have git installed for some reason, they might as well not even be aware of this functionality.

When not "pinning" the gitref, but only going by master/HEAD premake should/could keep track of that last commits hash and see if the remote repo has another more up-to-date version.

starkos commented 5 years ago

yes of course gitref could also work. My initial thought was to make it very granular to not force one behaviour on the user later on.

My concern is that is a script specifies both, which one wins? I don't like competing settings when we can avoid them.

Possible default to {prj.location}/dependencies/{GitRepoName} as this is plenty verbose.

I don't see why projects with a Git URL should behave differently than non-Git projects. I would prefer to avoid this "special" behavior.

Adding a gitdir would also be a good addition, although adding unneeded complexity to the final product in my eyes.

I wouldn't assume that the location of the generated project file (e.g. ExampleLibFromGit.vcxproj) is in the same place as the Git checkout of the source code. Keeping build files in their own folder and out of the source tree is a common pattern. So we'll need a way to specify both.

MaxKruse commented 5 years ago

My concern is that is a script specifies both, which one wins? I don't like competing settings when we can avoid them.

you are right. I was thinking about this in a user-case situation, not directly the implementation.

I don't see why projects with a Git URL should behave differently than non-Git projects. I would prefer to avoid this "special" behavior.

i am not quite sure what you mean by this. Even when "adding" an dependency to a project, my idea was that this isnt actually incorperated into the gitmodules file or the git structure itself, just the filesystem.

I wouldn't assume that the location of the generated project file (e.g. ExampleLibFromGit.vcxproj) is in the same place as the Git checkout of the source code. Keeping build files in their own folder and out of the source tree is a common pattern. So we'll need a way to specify both.

Regardless of setting gitdir or not, buildfiles could always be generated in the final destination of the cloned/downloaded main folder. I am also not sure if i understood Keeping build files in their own folder and out of the source tree is a common pattern. So we'll need a way to specify both. correct. Depending on how the user organizes his filestructure, we should not force any behaviour about locations, outside of the "here is the default place. if you dont like it, structure your project into a src folder", as i think that should be common sense to most project. And even if it is not, the project most likely has very few files, so the overview wouldnt be harmed.

ratzlaff commented 5 years ago

Some questions off the top of my head: I am going to call them submodules until the premake terminology is finalized

What if I want to build files from a submodule in multiple projects? What if I want to build more than one submodule into one project? Where does premake place the cloned submodule? How do I change where premake clones the submodule to? Why do I have to make a project just to clone a submodule?

starkos commented 5 years ago

Some questions off the top of my head:

All good questions, but it would improve the discussion if you would also offer some suggestions.

ratzlaff commented 5 years ago

What if I want to build files from a submodule in multiple projects?

I dont believe the gitsource command should be tied to a specific project or workspace. This is basically a 'git clone' and I would suggest that all gitsource commands be performed before a workspace is even started in premake.

What if I want to build more than one submodule into one project?

If all gitsources are specified and executed before workspace then defining projects is exactly the same as it is today.

Where does premake place the cloned submodule?

Since gitsource is a clone, I would emulate git's default behavior, which is to place the cloned files in a similarly named folder (without the .git extension, if present). Following premake's location rules, the default location would be right next to the premake5.lua file.

How do I change where premake clones the submodule to?

Specify a table as the argument to gitsource:

gitsource { "https://github.com/exampleUser/exampleLib", "external/example" }

Why do I have to make a project just to clone a submodule?

As stated above, I do not believe these repos cloned with gitsource should be tied to any particular project.

It occurs to me that a proof of concept (or even a full implementation) should be doable with os.execute() without having to modify any of premake's sources.