-
Notifications
You must be signed in to change notification settings - Fork 183
CI: Test Windows / Visual Studio 2022, and add automatic dependent repo resolution logic. #208
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
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ab77a59 to
9d2f37c
Compare
b06eaf3 to
56ba2ab
Compare
When compiling openEMS using Visual Studio with clang-cl,
the following error occurs:
openEMS/tools/array_ops.h(50,15): error: overloaded 'operator+'
must have at least one parameter of class or enumeration type
50 | inline __m128 operator + (__m128 a, __m128 b) {return _mm_add_ps(a, b);}
| ^
The same error also repeats for "operator-", "operator*", "operator/",
"operator+=", "operator-=", "operator*=", "operator/=".
Since it's clang-cl, the simplest fix is to use the GCC extension
codebase instead. When "clang" is running under "clang-cl" mode
(which is a MSVC-compatibility mode), the macro __GCC__ is not set,
but the macro __clang__ is.
This commit enables the GCC vector extension codepath for both
GCC and clang to fix the build.
Signed-off-by: Yifeng Li <tomli@tomli.me>
If `VTK_VERSION` is an empty string (because VTK is not installed),
the statement `if (${VTK_VERSION} VERSION_GREATER "9")` is evaluated
as `if (VERSION_GREATER "9")`, generating the following misleading
and confusing syntax error:
CMake Error at CMakeLists.txt:151 (if):
if given arguments:
"VERSION_GREATER" "9"
Unknown arguments specified
Quote `VTK_VERSION` to avoid the error.
Signed-off-by: Yifeng Li <tomli@tomli.me>
For the Linux matrix, use GitHub Actions native "env" block to define CXXFLAGS, not bash_profile. Signed-off-by: Yifeng Li <tomli@tomli.me>
Homebrew always warns that python3 and cmake are already installed, this causes alarm fatigue in the GitHub Actions Summary's "Annotations" panel, developers may miss other useful warnings. Signed-off-by: Yifeng Li <tomli@tomli.me>
f755cd6 to
f99bb09
Compare
The openEMS Project is a multi-repo project. Changes frequently affect multiple repos, with changes depending on each other. Forking a repo also means all related repos must be forked together, creating a poor contribution experience, since the CI pipeline doesn't work properly for them. This commit introduces automatic dependent-repo resolution logic to the CI/CD pipeline, with the following rules. 1. Want to develop a multi-repo change in CSXCAD and openEMS? Use the same branch name, they'll be tested together. 2. Want to send Pull Requests to both CSXCAD and openEMS? Use the same branch name in your fork, and open two individual Pull Requests against CSXCAD and openEMS. If both Pull Requests are opened, and the source branch name is the same, they'll be tested together. 3. Want to fork openEMS and develop it at the downstream? You can fork the only the repos you need. The CI/CD script automatically uses the project founder's repos as fall back for non-forked dependencies. You can override these dependencies by forking more repos. == Owner-then-Founder Dependency Lookup == If a git commit is pushed into a repo, or if a repo has received a Pull Request from a contributor, to build this repo, we need to look for the repo's dependencies. We check all dependencies one by one. If the repo's owner also has dependent repo under their GitHub account. If it's the case, the owner's copy is used as the dependency. If it's not the case, the founder account thliebig's copy is used as the dependency. This two-tier lookup solves several problems: 1. An experimenter can only fork openEMS without forking any dependencies. Since the CI/CD script falls back to the founder's repos for dependencies, their local repo's CI/CD works automatically. If they want to make a change to CSXCAD and openEMS at the same time, they only need to selectively fork CSXCAD, so that the "repo owner override" takes effect. At the same time, they can keep using the founder's fparser repo as a fallback without forking it. 2. Someone may send a Pull Request against a downstream fork itself, rather than the project founder. For example, I have a downstream openEMS fork named fasterEMS. If someone sends a Pull Request against my "fasterEMS/CSXCAD", my repo's CI/CD needs to use the same-owner repo "fasterEMS/fparser" as the dependency, not project founder's "thliebig/fparser". == Pull-Request Ganging == If a Pull Request "pr_primary" is submitted against the upstream repo "repo_primary", we check whether the same contributor has also opened another Pull Request "pr_dependency" against our dependency "repo_dependency", and whether both Pull Requests uses the same source branch name, such as "feature". If both conditions are met, we can say that two Pull Requests are "ganged", they are tested by CI/CD together. When testing "pr_primary" at "repo_primary", instead of using default repos as dependencies, we checkout the merge commit of "pr_secondary" at the "repo_secondary" as its dependency. For more than 2 repos, the same "ganged PR" logic also applies. If Pull-Request Ganging is activated, a warning is generated in the "Annotations" panel of the GitHub Actions Summary page, reminding developers to merge the dependent PR first before the main PR. == Branch Ganging == If a git commit is submitted to a non-default branch "feature" of repo "repo_primary", we check whether our dependency "repo_dependency" also has a branch named "feature". If this condition is met, we can say that two repo branches are "ganged", they are tested by CI/CD together. When testing the branch "feature" of "repo_primary", instead of using default branch "master" of "repo_dependency" as the dependency, we checkout the branch "feature" the "repo_dependency" instead. This allows testing multi-repo features together while it's in development. For more than 2 repos, the same "ganged branches" logic also applies. If Branch Ganging is activated, a warning is generated in the "Annotations" panel of the GitHub Actions Summary page, reminding developers that a different branch of the dependent repo is used for this test. == Implementation Details == This commit adds a new CI job called "Resolve Repo Dependencies", which is executed before all other jobs. This job calls the Python script "scripts/resolve_dependent_repos.py", which uses GitHub Actions variables and GitHub APIs to find the needed dependencies according to the conditions and contexts explained above. After the script finishes, it generates several output variables that contain the repoes and branches of all dependencies. These output variables are passed using the shell variable "$GITHUB_OUTPUT" (provided by GitHub Actions), later, all other jobs use these variable as their inputs for the "actions/checkout" steps. Signed-off-by: Yifeng Li <tomli@tomli.me>
This commit introduces a project manifest for managing Windows dependencies using vcpkg, the modern C/C++ package manager for Windows development. Although vcpkg is a Microsoft product, it's a free and open source package manager. In principle, vcpkg can also manage dependencies and even make binary releases on Unix-like systems, but this use case is untested and unsupported. Use at one's own risks. Currently, the use case is strictly for auto-building dependencies on Windows. Note: since we have to maintain the vcpkg pipeline anyway, perhaps it does make sense to reuse vcpkg for releasing binary packages for both Windows and Unix-like systems in the future, but this remains a speculative idea for now. Signed-off-by: Yifeng Li <tomli@tomli.me>
e547c5f to
a25f7ad
Compare
This commit introduces Continuous Integration for Windows with MSVC/clang-cl shipped in Visual Studio 2022. vcpkg is used to automatically build all dependencies from source, with the advantage of full automation, latest upstream version, perfect binary compatibility, and customizable build flags. However, the full source build takes a long time (like using Gentoo Portage or MacPorts), in this case, 2 hours. A vcpkg binary cache is used to speedup iterative development. GitHub Actions cache is immutable, we can't modify existing cache, so we use a last-recently logic: Before each run, the last-written cache with a given prefix is restored. After each run, a new cache with the same prefix and a different suffix is submitted to GitHub. It's GitHub's responsibility to delete old cache if 7 days have passed or after the total size exceeds 10 GiB. Signed-off-by: Yifeng Li <tomli@tomli.me>
Contributor
Author
|
Merge ready. Some remarks.
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Introduction
This Pull Request introduces two major new features and performs some housekeeping tasks to the CI/CD pipeline:
Add automatic dependent-repo resolution logic.
Test Windows / Visual Studio 2022 using MSVC and clang-cl.
Miscellaneous housekeeping changes.
Not implemented:
To be implement in the future.
CI: Add automatic dependent repo resolution logic.
The openEMS Project is a multi-repo project. Changes frequently affect multiple repos, with changes depending on each other. Forking a repo also means all related repos must be forked together, creating a poor contribution experience, since the CI pipeline doesn't work properly for them.
This commit introduces automatic dependent-repo resolution logic to the CI/CD pipeline, with the following rules.
Want to develop a multi-repo change in CSXCAD and openEMS? Use the same branch name, they'll be tested together.
Want to send Pull Requests to both CSXCAD and openEMS? Use the same branch name in your fork, and open two individual Pull Requests against CSXCAD and openEMS. If both Pull Requests are opened, and the source branch name is the same, they'll be tested together.
Want to fork openEMS and develop it at the downstream? You can fork the only the repos you need. The CI/CD script automatically uses the project founder's repos as fall back for non-forked dependencies. You can override these dependencies by forking more repos.
Owner-then-Founder Dependency Lookup
If a git commit is pushed into a repo, or if a repo has received a Pull Request from a contributor, to build this repo, we need to look for the repo's dependencies. We check all dependencies one by one. If the repo's owner also has dependent repo under their GitHub account. If it's the case, the owner's copy is used as the dependency. If it's not the case, the founder account thliebig's copy is used as the dependency.
This two-tier lookup solves several problems:
An experimenter can only fork openEMS without forking any dependencies. Since the CI/CD script falls back to the founder's repos for dependencies, their local repo's CI/CD works automatically. If they want to make a change to CSXCAD and openEMS at the same time, they only need to selectively fork CSXCAD, so that the "repo owner override" takes effect. At the same time, they can keep using the founder's fparser repo as a fallback without forking it.
Someone may send a Pull Request against a downstream fork itself, rather than the project founder. For example, I have a downstream openEMS fork named fasterEMS. If someone sends a Pull Request against my "fasterEMS/CSXCAD", my repo's CI/CD needs to use the same-owner repo "fasterEMS/fparser" as the dependency, not project founder's "thliebig/fparser".
Pull-Request Ganging
If a Pull Request "pr_primary" is submitted against the upstream repo "repo_primary", we check whether the same contributor has also opened another Pull Request "pr_dependency" against our dependency "repo_dependency", and whether both Pull Requests uses the same source branch name, such as "feature". If both conditions are met, we can say that two Pull Requests are "ganged", they are tested by CI/CD together. When testing "pr_primary" at "repo_primary", instead of using default repos as dependencies, we checkout the merge commit of "pr_secondary" at the "repo_secondary" as its dependency.
For more than 2 repos, the same "ganged PR" logic also applies.
If Pull-Request Ganging is activated, a warning is generated in the "Annotations" panel of the GitHub Actions Summary page, reminding developers to merge the dependent PR first before the main PR.
Branch Ganging
If a git commit is submitted to a non-default branch "feature" of repo "repo_primary", we check whether our dependency "repo_dependency" also has a branch named "feature".
If this condition is met, we can say that two repo branches are "ganged", they are tested by CI/CD together. When testing the branch "feature" of "repo_primary", instead of using default branch "master" of "repo_dependency" as the dependency, we checkout the branch "feature" the "repo_dependency" instead.
This allows testing multi-repo features together while it's in development. For more than 2 repos, the same "ganged branches" logic also applies.
If Branch Ganging is activated, a warning is generated in the "Annotations" panel of the GitHub Actions Summary page, reminding developers that a different branch of the dependent repo is used for this test.
Implementation Details
This commit adds a new CI job called "Resolve Repo Dependencies", which is executed before all other jobs. This job calls the Python script "scripts/resolve_dependent_repos.py", which uses GitHub Actions variables and GitHub APIs to find the needed dependencies according to the conditions and contexts explained above.
After the script finishes, it generates several output variables that contain the repoes and branches of all dependencies. These output variables are passed using the shell variable "$GITHUB_OUTPUT" (provided by GitHub Actions), later, all other jobs use these variable as their inputs for the "actions/checkout" steps.
vcpkg
tools/array_ops.h: use GCC extension for clang-cl
When compiling openEMS using Visual Studio with clang-cl, the following error occurs:
The same error also repeats for
operator-,operator*,operator/,operator+=,operator-=,operator*=,operator/=.Since it's clang-cl, the simplest fix is to use the GCC extension codebase instead. When "clang" is running under "clang-cl" mode (which is a MSVC-compatibility mode), the macro
__GCC__is not set, but the macro__clang__is.This commit enables the GCC vector extension codepath for both GCC and clang to fix the build.
vcpkg: add manifest for managing Windows dependencies.
This commit introduces a project manifest for managing Windows dependencies using vcpkg, the modern C/C++ package manager for Windows development.
Although vcpkg is a Microsoft product, it's a free and open source package manager. In principle, vcpkg can also manage dependencies and even make binary releases on Unix-like systems, but this use case is untested and unsupported. Use at one's own risks. Currently, the use case is strictly for auto-building dependencies on Windows.
Note: since we have to maintain the vcpkg pipeline anyway, perhaps it does make sense to reuse vcpkg for releasing binary packages for both Windows and Unix-like systems in the future, but this remains a speculative idea for now.
CI: Windows MSVC/clang-cl Test using Visual Studio 2022.
This commit introduces Continuous Integration for Windows with MSVC/clang-cl shipped in Visual Studio 2022.
vcpkg is used to automatically build all dependencies from source, with the advantage of full automation, latest upstream version, perfect binary compatibility, and customizable build flags.
However, the full source build takes a long time (like using Gentoo Portage or MacPorts), in this case, 2 hours. A vcpkg binary cache is used to speedup iterative development. GitHub Actions cache is immutable, we can't modify existing cache, so we use a last-recently logic: Before each run, the last-written cache with a given prefix is restored. After each run, a new cache with the same prefix and a different suffix is submitted to GitHub. It's GitHub's responsibility to delete old cache if 7 days have passed or after the total size exceeds 10 GiB.
Housekeeping
CI: use GitHub Actions env block, not bash_profile.
For the Linux matrix, use GitHub Actions native "env" block to define CXXFLAGS, not bash_profile.
CI: Don't install python3 and cmake on macOS.
Homebrew always warns that python3 and cmake are already installed, this causes warning fatigue in the GitHub Actions Summary's "Annotations" panel, developers may miss other useful warnings.
CMakeLists.txt: quote VTK_VERSION
If
VTK_VERSIONis an empty string (because VTK is not installed), the statementif (${VTK_VERSION} VERSION_GREATER "9")is evaluated asif (VERSION_GREATER "9"), generating the following misleading and confusing syntax error:Quote
VTK_VERSIONto avoid the error.