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

CMake build system for git #2580

Closed
wants to merge 10 commits into from

Conversation

SibiSiddharthan
Copy link

This is cmake build system for git.
Tested platforms
MinGW GCC 9.2
Clang 9
Visual Studio 2015,2019

@dscho
Copy link
Member

dscho commented Apr 10, 2020

Whoa, that's a pretty big change.

To be honest, I am not such a big fan of CMake, but I figure that this is not exactly intrusive a change, as it merely adds a file.

The trick will be to keep it working, and I bet that the best idea would be to adjust the vs-build job in .github/workflows/main.yml to use CMake instead of make vcxproj.

Of course, we will still have to take care of building the command-list.h file, which is done via a shell script. So we need to make sure that we call this through the Git for Windows Bash that is installed on the build agents. You can do that via:

- name: build
  shell: bash
  run: ...

Also, please use your real name and real email address for the committer/author information.

Looking forward to see this progress!

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 10, 2020 via email

@dscho
Copy link
Member

dscho commented Apr 10, 2020

The cmake script generates command-list.h through execute process. On windows you need to git-bash installed and have sh.exe in your path.

Indeed.

That is precisely what I meant, when I suggested to adjust the GitHub workflow to use the new CMake workflow to verify that it keeps working.

@dscho
Copy link
Member

dscho commented Apr 10, 2020

Thank you for working on this!

It looks as if CMake was unable to find the vcpkg-provided artifacts, right?

Also, please do modify the vs-build job in .github/workflows/main.yml instead of adding a new file.

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 10, 2020 via email

@dscho
Copy link
Member

dscho commented Apr 10, 2020

And yes, I am not able find the artifacts. Can you tell me the directory in which the artifacts are extracted to?

They should be extracted in-place, where they would have been put by vcpkg.exe: compat\vcbuild\vcpkg\installed, I think. You should download the artifacts from the latest run of https://dev.azure.com/git/git/_build?definitionId=9&_a=summary to see for yourself (and also to be able to test locally).

And how do I stop triggering GitHub actions on git-for-windows/git?

You can stop it from triggering by removing the pull_request from .github/workflows/main.yml. You can do that in a temporary commit that you then revert before we merge this PR.

If I were you, I would also remove the jobs that you're not interested in, i.e. everything except vs-build and vs-test. Oh, and please do remove .github/workflows/ccpp.yml. It would be best to already work in main.yml, not in a separate file.

@dscho
Copy link
Member

dscho commented Apr 11, 2020

I have to admit that it is exciting to watch the progress from the sidelines...

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 11, 2020 via email

@dscho
Copy link
Member

dscho commented Apr 11, 2020

Well, the build is now succeeding in the CI system, now I have to make the tests to work.

If you worked directly in main.yml, I am rather certain that there is nothing else to do. Those tests already worked before, and all this PR changes is the way the Visual Studio solution is generated, right?

@dscho
Copy link
Member

dscho commented Apr 11, 2020

If you compare the vs-artifacts from https://github.com/SibiSiddharthan/git/runs/578782714 to the latest successful run triggered by a push to Git for Windows' master (https://github.com/git-for-windows/git/actions/runs/73638378), you will realize three things:

  • The artifacts.tar.gz files are of a substantially different size: 201MB vs 14MB. The difference is most likely due to the built-ins not being hardlinked to git.exe but being verbatim copies.

  • The scripts that are bundled in the failed run all have CR/LF line endings, the one from the successful run have LF-only line endings.

  • The bin-wrappers/ scripts in the failed run define GIT_EXEC_PATH='.' always. The successful run's have this instead:

    test -n "${GIT_EXEC_PATH##*:*}" ||
                GIT_EXEC_PATH="$(cygpath -u "$GIT_EXEC_PATH")"

Related to the last point, there is also a difference in how the environment variables GIT_TEMPLATE_DIR, GITPERLLIB, GIT_TEXTDOMAINDIRandPATHare defined. As an example, the full diff ofbin-wrappers/git`:

diff --git a/succ/bin-wrappers/git b/unsuc/bin-wrappers/git
index bbc9885..5410af4 100644
--- a/succ/bin-wrappers/git
+++ b/unsuc/bin-wrappers/git
@@ -4,20 +4,19 @@
 # to run test suite against sandbox, but with only bindir-installed
 # executables in PATH.  The Makefile copies this into various
 # files in bin-wrappers, substituting
-# /d/a/git/git and git.exe.
+# . and git.exe.

-test -n "${GIT_EXEC_PATH##*:*}" ||
-               GIT_EXEC_PATH="$(cygpath -u "$GIT_EXEC_PATH")"
+GIT_EXEC_PATH='.'
 if test -n "$NO_SET_GIT_TEMPLATE_DIR"
 then
        unset GIT_TEMPLATE_DIR
 else
-       GIT_TEMPLATE_DIR="$GIT_EXEC_PATH"'/templates/blt'
+       GIT_TEMPLATE_DIR='./templates/blt'
        export GIT_TEMPLATE_DIR
 fi
-GITPERLLIB="$GIT_EXEC_PATH"'/perl/build/lib'"${GITPERLLIB:+:$GITPERLLIB}"
-GIT_TEXTDOMAINDIR="$GIT_EXEC_PATH"'/po/build/locale'
-PATH="$GIT_EXEC_PATH"'/bin-wrappers:'"$PATH"
+GITPERLLIB='./perl/build/lib'"${GITPERLLIB:+:$GITPERLLIB}"
+GIT_TEXTDOMAINDIR='./po/build/locale'
+PATH='./bin-wrappers:'"$PATH"

The reason for those modifications lives here: https://github.com/git-for-windows/git/blob/v2.26.0.windows.1/config.mak.uname#L805-L823

I agree that this is not particularly elegant, and should probably be fixed in wrap-for-bin.sh instead. At some stage I made a mental note about that, but had totally forgotten in the meantime.

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 11, 2020 via email

@dscho
Copy link
Member

dscho commented Apr 11, 2020

The windows build now works. Looks like I had to add invalidcontinue.obj to the link options, which I had no idea about.

You're right. I had forgotten all about that.

In the CI when I try to create links in the build phase, when untar(ing) tar is not able to restore the links. So I am sticking with verbatim copies for now.

Are those hardlinks, or symlinks? I think only the former will work (e.g. mklink /h git-add.exe git.exe).

The tests now run, but I get a failure on t2024 in the CI which I don’t get in my system. The only test failures I get in my system (with NO_GETTEXT) are t0060 -> which is due to ENSURE_MSYSTEM_IS_SET and t2040 -> I think this has to do with the shell

Can you point me to verbose logs? It's hard to guess based on that description of a test failure.

With respect to the main.yml should I create a separate task like vs-build-cmake or should I edit vs-build itself. Please advice.

I would recommend to replace the make vcxproj step in the vs-build job with a CMake one. In main.yml.

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 12, 2020 via email

@dscho
Copy link
Member

dscho commented Apr 12, 2020

Would it be possible to include the trace of the failed tests (i.e. the part preceding the code you showed)?

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 12, 2020 via email

@dscho
Copy link
Member

dscho commented Apr 12, 2020

The builds works now. Yippee!!!

Cool!

T0060-path-utils-sh was failing because it was not able to load libiconv.dll

And that .dll wasn't included in the artifacts.tar.gz?

T2040-checkout-symlink-attr.h is a MINGW only test, so no need to bother with it on MSVC, am I right?

Actually, in Git's test suite, the MINGW prereq stands for "Windows build of Git, but not Cygwin".

So I think we still need that test to pass.

The other tests that were failing in the CI were because of (NO_PERL=1) .

Oh, and the tests were not run with NO_PERL? We need to do that, as the test suite already takes way too long to run on Windows.

The tests worked fine on my system with perl, but fail in the CI. Can you explain why?. Is it because the tar doesn't include the .pm files?

It probably is. And we don't really want to include them.

For the merge, I have two dummy commits which are unsigned. Should I rebase with the original PR(commit) and add these changes, or is it fine?

Are those merge commits necessary? Otherwise I'd just git reset --hard to the commit before. Otherwise, rebase.

The PR build should test a merge, anyway.

Clang also works now, so should I add a Clang build to main.yml?

Personally, I wouldn't. If we really want to test that, I would modify linux-clang to use it, but last time there was a discussion on the Git mailing list about CMake, I don't think there was a lot of enthusiam for it, so I'd try to leave linux-clang alone.

The benefit for MSVC, OTOH, is obvious, so changing vs-build to use CMake is very desirable.

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 12, 2020 via email

@SibiSiddharthan
Copy link
Author

The cmake build works. All tests pass. The generated artifacts use hardlinks now.

@dscho
Copy link
Member

dscho commented Apr 13, 2020

Excellent!

About the t2040 failure: do you use native symlinks in MSYS2 by default? IIRC you have to set the environment variable MSYS to something containing the substring "nativelinks". That would explain why this test case is run at all. I don't think that our CI runs with that flag.

The reason I prefer clang is because it is a better compiler than MSVC. Hope to see it added soon.

You mean Git for Windows? I dabbled with the idea, but mingw-w64-clang is not installed in Git for Windows SDK by default, and it would add a noticeable amount of megabytes to the already large SDK.

Besides, there was rumour in the MSYS2 project that they might want to switch from GCC to clang in their own MINGW packages, and I was kinda thinking that this switch would make for a perfect excuse to do the same for mingw-w64-git.

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 13, 2020 via email

Copy link
Member

@dscho dscho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, what a gigantic amount of work! Well done.

I offered a huge amount of comments, suggestions, questions in response, and in addition I would like to propose a commit structure to make this easier to review on the Git mailing list (where I want to send this eventually):

  • preparatory patches (such as modifying t/test-lib.sh to allow for the build directory being separate from the source directory)
  • introduce a basic CMakeLists.txt. Maybe just the bare-bones one that can build the executables, without gettext, only on Linux.
  • a bunch of commits to enhance CMakeLists.txt in easy-to-describe steps, e.g. add support for gettext, also "build" the templates, support building with macOS, support building with MSVC, support building with clang on Windows, etc
  • a final patch that modifies .github/workflows/main.yml so that it exercises the CMake-based build in vs-build, mentioning in the commit message why we do it, why only here, that having this in the CI/PR builds will make it easier to keep this working, and whatever else we think might be useful to keep in mind for the keen reader.

How does that sound?

CMakeLists.txt Show resolved Hide resolved
#
# Copyright (c) 2020 Sibi Siddharthan
#
cmake_minimum_required(VERSION 3.15)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to https://blog.kitware.com/cmake-3-15-0-available-for-download/, that version is not even a year old. Maybe we can lower the expectations? Or are there features required by this file that are available only in CMake v3.15.0 and newer?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the cmake docs, the lowest I can go is 3.12.4.(Need to test) This was the first release with add_compile_options() which is used throughout build script. This means I don't have a common way of creating create symlinks anymore. I think this is okay, because in CI creating hardlinks is better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the " Added support for MSVC and clang on Windows" commit (whose first line should probably read more like "cmake: support MSVC and clang on Windows") seems to require CMake v3.15, could you describe in that commit's message why?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, since I think of this right now: the biggest difference between the support for GCC (MINGW) on Windows and the support for MSVC/clang on Windows is that the former is expected to be built and run in Git for Windows' SDK, and the latter can easily run without the full SDK, apart from the compiler it just needs a Git Bash from an end-user Git for Windows installation (which is much more light-weight than the full SDK).

I think this is really a distinction worth mentioning in both of the commits, the one introducing support for GCC (MINGW) and the one introducing support for MSVC/clang.

Also, I think that we may want to auto-initialize the vcpkg system similar to https://github.com/git-for-windows/git/blob/v2.26.1.windows.1/config.mak.uname#L29 (i.e. we should run compat/vcbuild/vcpkg_install.bat unless compat/vcbuild/vcpkg/installed/ exists).

CMakeLists.txt Outdated Show resolved Hide resolved
CMakeLists.txt Show resolved Hide resolved
CMakeLists.txt Outdated Show resolved Hide resolved
CMakeLists.txt Outdated Show resolved Hide resolved
CMakeLists.txt Outdated Show resolved Hide resolved
CMakeLists.txt Show resolved Hide resolved
CMakeLists.txt Show resolved Hide resolved
CMakeLists.txt Outdated Show resolved Hide resolved
@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 13, 2020

Thanks for your review,
Steps

  1. Do a linux only build. No install. No generating the script files. No testing.But keep all the functions and header checks.
  2. For linux only add generating scripts.
  3. For linux only add install
  4. For linux only add testing
  5. add relocatable tests.
  6. Add basic windows build with mingw with the conditional checks
  7. Add install for windows
  8. Add support for MSVC and clang.
  9. Add CI specific changes for test to work there for MSVC.
  10. Add apple support

Does this roadmap sound good to you?
So now how should I proceed. Should I close this pull request and commit files in this specific order.
Or should I just submit patches for these steps. Please advice.

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 13, 2020 via email

@dscho
Copy link
Member

dscho commented Apr 14, 2020

That roadmap sounds good. I'd suggest to follow https://git-scm.com/docs/git-rebase#_splitting_commits to split it up, then force-push. No need to open a new PR.

About the hardlinks and tar: that is a side effect. The real reason is really that Git's original Makefile does it that way.

@SibiSiddharthan
Copy link
Author

I have also tested the CMake script with the git/git repo. There are only 3 changes that I have to make for it to work there(These changes are undoing the compatibility stuff for this fork and git/git). So if I make these changes the script would not work here.
Do you think I should make these changes an raise a PR to gitgitgadget/git ? Please Advice.

@dscho
Copy link
Member

dscho commented Apr 21, 2020

Do you think I should make these changes an raise a PR to gitgitgadget/git ?

Yes, I think that would be an excellent idea!

You will probably want to use either next or dd/ci-swap-azure-pipelines-with-github-actions as the base branch (preferably the latter, it introduced the support for GitHub Actions in git/git, you will find that branch at https://github.com/gitgitgadget/git).

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Apr 22, 2020 via email

@dscho
Copy link
Member

dscho commented Apr 23, 2020

git/next and dd/ci-swap-azure-pipelines-with-github-actions are same(as of today).

Not quite. The former includes the latter, but the former includes much more in addition.

Just to clarify any PRs I raise to gitgitgadget/git to any branch will be in the mailing lists (git@vger.kernel.org), right?

Yes, you will need to /submit it (which will send it to the mailing list, as GitGitGadget described in the welcome message.

And, I tested without the CI specific blocks, since each job takes place in the same directory(wrt path) the build works.

Yes, it's good that the CI-specific blocks are gone.

It would still be good to support (somehow, e.g. using the "t/test-lib.sh: set GIT_EXEC_PATH only unless already set" strategy I suggested) to support it, but that can come later, I think.

@SibiSiddharthan
Copy link
Author

@dscho
Regarding the gitgitgaget/git PR discussion, they are okay with adding the CMakeLists.txt to contrib/buildsystems. What are the next steps to be done?

Regarding this PR, do you want a CMake script specific to this repo? (depending on Makefiles on sources ofcourse).

@dscho
Copy link
Member

dscho commented Apr 29, 2020

@SibiSiddharthan oh, just go ahead with contrib/ and work with the Git mailing list to get it integrated into next (and then hopefully into master). Once things are stable enough on that end, we can always come back to this here PR and integrate the patches into Git for Windows' fork.

@dscho
Copy link
Member

dscho commented May 1, 2020

Oh, there is one more thing that I would like to address, but I struggle to find the time: the portable Git should be as fast as git-sdk-64-minimal, if not faster. My guess is that if we replace /etc/profile with

export MSYSTEM=MINGW64
export PATH=/mingw64/bin:/usr/bin/:/usr/bin/core_perl:$PATH

then it should be as fast.

@SibiSiddharthan
Copy link
Author

It is not about git-sdk-64-minimal or git-64-portable that causes the slowdown.
It is because of this
usr\bin\bash.exe -lc ...
vs
git-cmd.exe --command=usr\bin\bash.exe -lc ...

Calling git-cmd then calling bash is the problem.

@dscho
Copy link
Member

dscho commented May 2, 2020

It is not about git-sdk-64-minimal or git-64-portable that causes the slowdown.
It is because of this
usr\bin\bash.exe -lc ...
vs
git-cmd.exe --command=usr\bin\bash.exe -lc ...

Calling git-cmd then calling bash is the problem.

I don't actually think that git-cmd.exe is the problem. It is a very tiny wrapper that simply sets MSYSTEM and adjusts PATH, then calls bash.exe and waits for it to finish.

But there is this a bigger difference between git-sdk-64-minimal and portable Git: the /etc/profile is overwritten with a trivial version in git-sdk-64-minimal, and /etc/bash.bashrc is completely missing from git-sdk-64-minimal!

That's why I think that overwriting git-64-portable's /etc/profile might reinstate the performance.

It is also quite possible, though, that the /etc/bash.bashrc file needs to be removed. Technically, this should not change a thing because it returns early when not called interactively. But the MSYS2 runtime does do funny things with seemingly trivial operations, therefore it might make a huge difference whether we delete the file or not.

@SibiSiddharthan
Copy link
Author

@dscho The CMake patch series has been merged into ss/cmake-build. Thank you for your support!!!

@dscho
Copy link
Member

dscho commented Jun 13, 2020

Yeah!

@git-for-windows-ci git-for-windows-ci changed the base branch from master to main June 17, 2020 18:10
@SibiSiddharthan
Copy link
Author

@dscho quite a few of the tests are failing for vs-build in the CI.
Every test passes in my local machine.
I have no clue what is happening. Everything was fine 7 days ago.

@SibiSiddharthan
Copy link
Author

@dscho I think I have found the issue causing some tests to fail, it is related to multibyte characters.
I ran the tests that failed in the CI locally with the CI built artifacts, the errors arise due to encoding changes and multibyte characters. Do you have any idea what is causing them?

When I do a local compile with the same version of CMake , compiler I get no errors.

@dscho
Copy link
Member

dscho commented Jun 22, 2020

quite a few of the tests are failing for vs-build in the CI.

Can you give me a link to the log?

@SibiSiddharthan
Copy link
Author

quite a few of the tests are failing for vs-build in the CI.
Can you give me a link to the log?

This is one of the failed runs.
https://github.com/SibiSiddharthan/git/actions/runs/141279361

@dscho
Copy link
Member

dscho commented Jun 23, 2020

This is one of the failed runs.
https://github.com/SibiSiddharthan/git/actions/runs/141279361

I see this in the log:

2020-06-19T21:02:04.9100919Z error: cannot convert from ISO8859-1 to UTF-8

Which suggests to me that this might be compiled without iconv support. But then I see this line:

2020-06-19T20:47:39.3219440Z -- Found Iconv: C:/Program Files/PostgreSQL/12/lib/iconv.lib  

It would seem to me that it looks at the wrong iconv, and that might be the entire reason why it does not work?

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Jun 23, 2020

2020-06-19T20:47:39.3219440Z -- Found Iconv: C:/Program Files/PostgreSQL/12/lib/iconv.lib


It would seem to me that it looks at the wrong `iconv`, and that might be the entire reason why it does not work?

Yep, this is the issue. Don't understand why it is selecting that libiconv. The library search paths start with CMAKE_PREFIX_PATH, which I specify. Looks like I need to override libiconv location manually.
Thanks

Now I am worried, in the future if the github environment installs another package which overrides one of the required libraries, a similar problem can arise. I think it is better to specify the location of the libraries manually for avoiding future issues like these.

@mathstuf
Copy link

If you use CMake 3.17 and up, --debug-find can show you the search paths it is looking for to know why it prefers that directory.

@dscho
Copy link
Member

dscho commented Jun 23, 2020

. The library search paths start with CMAKE_PREFIX_PATH, which I specify. Looks like I need to override libiconv location manually.

Is there maybe a way to dump the actual search path that's used? I am not so sure that the paths we want to use are prefixed, they might be appended instead.

If you use CMake 3.17 and up, --debug-find can show you the search paths it is looking for to know why it prefers that directory.

Ah, that's exactly the answer ;-)

Now I am worried, in the future if the github environment installs another package which overrides one of the required libraries, a similar problem can arise. I think it is better to specify the location of the libraries manually for avoiding future issues like these.

I would like to avoid that, honestly. We might need to find a way to hard-code the search path, though, so that none but the pre-built libraries are picked up.

@SibiSiddharthan
Copy link
Author

SibiSiddharthan commented Jun 24, 2020

Figured out why cmake was finding postgresql's iconv.lib, instead of vcpkg's one. This is because cmake prefers iconv.lib to libiconv.lib in their implementation. Even though it found vcpkg's libiconv.lib first it preferred the other one.

@mathstuf
Copy link

It's hard to tell in general which name is preferred overall because that is a deployment decision, not something CMake can just assume. Given that there's no real way to express this preference today, I'd suggest (in decreasing order of preference):

  • removing the postgres prefix from CMake's search paths (though I presume it is there for other reasons?)
  • hard-coding the path when configuring
  • change FindIconv.cmake to use NAMES_PER_DIR to prioritize search locations over library names
  • adding a Iconv_USE_STATIC_LIBS option to FindIconv.cmake to only search for one of the two names on Windows (harder to implement on Linux and macOS though). Maybe Iconv_PREFER_STATIC_LIBS would be better? Still requires some extension list manipulation on non-Windows though.

@SibiSiddharthan
Copy link
Author

  • hard-coding the path when configuring

This is what I am using as a workaround in the CI.

  • change FindIconv.cmake to use NAMES_PER_DIR to prioritize search locations over library names

Is there a way ,say a variable we can set so that all calls to find_* commands use NAMES_PER_DIR?

@mathstuf
Copy link

Is there a way ,say a variable we can set so that all calls to find_* commands use NAMES_PER_DIR?

No, each package is different in this way. It should probably be used for any find_library call which has multiple names for a library on a given platform, but hasn't been added because conflicts actually happen so rarely. These CI images which ship a bunch of things that aren't normally seen together is a new thing that might make these kinds of details actually get recognized and fixed now.

@dscho
Copy link
Member

dscho commented Oct 6, 2020

Thank you, @SibiSiddharthan, for your incredible patience and energy that you put into this project. Through your hard work, this feature entered git/git first and is now part of v2.29.0-rc0.windows.1.

🎉

@dscho dscho closed this Oct 6, 2020
@SibiSiddharthan
Copy link
Author

@dscho thanks a lot for your support too.

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

Successfully merging this pull request may close these issues.

4 participants