-
Notifications
You must be signed in to change notification settings - Fork 40
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
Setting shell default for Windows hosts in cross-platform matrix #102
Comments
strategy:
matrix:
include:
- { os: windows, shell: msys2 },
- { os: ubuntu, shell: bash },
- { os: macos, shell: bash },
runs-on: ${{ matrix.os }}
defaults:
run:
shell: ${{ matrix.shell} {0}
steps: WRT selecting the CMake generator, I don't really understand why you are using an specific Action for that, given that all you need to do is set an environment variable. Unless the Action is aware of how MSYS2 works, the envvar won't be visible. You'd need to - name: Build
run: |
CMAKE_GENERATOR='Unix Makefiles'
if [ "${{ matrix.org }}" = "windows" ]; then
CMAKE_GENERATOR='MSYS Makefiles'
fi
cmake -B build -S . -G "$CMAKE_GENERATOR" ... |
Oooh, clevvvverrrr! If the It kind of takes the "matrix" out of it, having to list each permutation individually, which is kind of too bad. (I currently have an 8-way matrix set up, four OS builds × the two compiler toolchains, and am considering adding more dimensions.) But, still, it's way more workable than anything I was trying! Thanks, this should be pretty much exactly what I need. I'll just have to get over my purity-of-configuration hangup. 😉
Oh, sure, now that I'm conditionalizing the scripts anyway I can do that, but remember that originally I was trying to keep the scripts OS-agnostic. Plus, having the selected generator available in a yaml context means that I could use it for other purposes. I already use the matrix dimensions as part of the asset naming in my In fact, I stopped setting the - name: Build (Unix)
if: ${{ runner.os != 'windows' }}
run: |
if [ "X${{ runner.os }}X${{ matrix.compiler }}X" == "XmacOSXclangX" ]; then
export CMAKE_EXTRA="-DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++ -DCMAKE_SHARED_LINKER_FLAGS=-stdlib=libc++ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9"; fi
if [ "x${{ matrix.compiler }}" == "xgcc" ]; then
export CC=gcc CXX=g++; else export CC=clang CXX=clang++; fi
cmake -B build -S . $(etc...) ${CMAKE_EXTRA} (I currently have the Windows scripting split out to a separate Thanks again! |
(Of course, thanks to your explicit-strategy-lanes idea, I could also be setting both compiler envvars that way...) strategy:
matrix:
include:
- { os: windows, shell: msys2, cc: gcc, cxx: g++ },
- { os: windows, shell: msys2, cc: clang, cxx: clang++ },
- { os: ubuntu, shell: bash, cc: gcc, cxx: g++ },
- { os: ubuntu, shell: bash, cc: clang, cxx: clang++ },
- { os: macos, shell: bash, cc: gcc, cxx: g++ },
- { os: macos, shell: bash, cc: clang, cxx: clang++ },
env:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }} |
I agree that using matrices is not always as intuitive as it should be. Yet, I believe that main missing feature preventing proper code reuse is YAML anchors. That would make composing matrices, steps or jobs much easier. Regarding the proposed solution, you read too fast and skipped the key concept! Pay attention: we replaced a value of type string with an object containing two fields of type string. The fact that I used strategy:
matrix:
sys:
- { os: windows, shell: msys2 },
- { os: ubuntu, shell: bash },
- { os: macos, shell: bash },
comp:
- { cc: gcc, cxx: g++ },
- { cc: clang, cxx: clang++ },
env:
CC: ${{ matrix.comp.cc }}
CXX: ${{ matrix.comp.cxx }}
runs-on: ${{ matrix.sys.os }}
defaults:
run:
shell: ${{ matrix.sys.shell }} {0} Moreover, you might want to set Overall, although not ideal, you can make pretty complex setups to be readable. WRT setting environment variables, the point is not the syntax, or whether to have them defined as YAML values (that's ok). The point is that msys2 shells are "isolated" by default; i.e. variables from the environment are not inherited. Therefore, it's rather pointless to set them outside. The CC and CXX envvars in the code block above won't be seen by msys2. See https://github.com/msys2/setup-msys2#path-type and #98. |
@ferdnyc Regard the "matrix", you can still somewhat pull off the matrix but it'll be a little ugly:
And then instead of As for cross-platform builds, you'll have trouble with some environment variables. The correct way to add environment variable in one step for them to be used in another step is to add a line like However, that modifies the environment variables in Windows. msys2 will inherit all all those environment variables into the bash environment except for PATH, LD_LIBRARY_PATH, PKG_CONFIG_PATH, and maybe others, too. So if you want to use GITHUB_ENV and GITHUB_PATH but have them work inside of msys, you need to kludge something. I wrote that kludge and it's horrific but it works. Here's how it looks:
It's in use currently in the actions: https://github.com/pcb2gcode/pcb2gcode/actions I didn't think of @eine solution for specifying the shell in the matrix and I'm kicking myself for not realizing it! Wow! I think that with my above kludge along with the matrix shell variable, I think that I might be able to have a single CI that does both Windows and Linux. Wow! I'm excited to try it. |
No, trust me, no matter how slowly I'd read your response, I'd never have made it there all on my own. Not all the way from listing out combinations explicitly with In fact, it feels almost like you shouldn't be able to do that. It certainly doesn't work for most other jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
compiler:
- { cc: gcc, cxx: g++ }
- { cc: clang, cxx: clang++ } Nevertheless, it does indeed work. In fact, so does this (which I find even more confounding), and despite the roundabout approach to it, results in exactly the correct six-way matrix of two compiler suites per OS, with the correct shell being assigned to each OS: jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest]
shell: [bash]
compiler:
- { cc: gcc, cxx: g++ }
- { cc: clang, cxx: clang++ }
include:
- os: windows-latest
shell: 'msys2 {0}'
compiler: { cc: gcc, cxx: g++ }
- os: windows-latest
shell: 'msys2 {0}'
compiler: { cc: clang, cxx: clang++ } ...But Github screams really mightily about the syntax of the And if you define the But it's a daft thing to do anyway. It's certainly not any better than any of the previous iterations, and in fact it's significantly worse than some of them. My point here isn't to present this as anything a sane person would use. I'm just illustrating that matrix syntax is not merely confusing, it's actually non-conformant to the officially-documented grammar and syntax checking. It's even possible that the syntax in question is exploiting a bug, not making use of a feature. |
Huh, I take that part back. Must've been some other syntax error, first time I tried it. In truth, even this works exactly the way you'd want it to. (But still gets flagged as a pair of syntax errors, by the editor.): jobs:
build:
runs-on: '${{ matrix.os.os }}-latest'
strategy:
matrix:
os:
- { os: windows, shell: msys2 }
- { os: ubuntu, shell: bash }
- { os: macos, shell: bash }
comp:
- { cc: gcc, cxx: g++ }
- { cc: clang, cxx: clang++ }
defaults:
run:
shell: '${{ matrix.os.shell }} {0}'
env:
CC: ${{ matrix.comp.cc }}
CXX: ${{ matrix.comp.cxx }} |
Check it out, windows/macos/ubuntu in a unified list of GitHub workflow steps: #98 (comment) |
@ferdnyc, you might be correct thinking it's not a feature that GitHub expected to be used. However, I wouldn't call it a bug in the workflow, but in the documentation and/or the grammar/syntax checking. If the syntax is valid YAML and the runner can understand it, limiting it because missing semantic support in the checker is not sensible. I'd say, use it carefully, but don't expect workflow syntax checking to be complete/up to date.
I forgot to remove trailing |
Same here (after I shake out some last bugs, tho, related to compilation failures on Windows, rather than workflow failures). Oh, and to answer the question @eine asked a while back, I now remember why I was using - name: Select CMake generator
uses: haya14busa/action-cond@v1
id: generator
with:
cond: ${{ runner.os == 'Windows' }}
if_true: 'MSYS Makefiles'
if_false: 'Unix Makefiles' and then dropping it directly into the cmake -G "${{ steps.generator.outputs.value }}" is simplicity itself. I am very lazy and very willing to take the easy route, on things like that. 😁
That's fair. And, I wasn't calling it a bug in the workflow exactly — rather, it may be a bug in their yaml processing, that it works when it's not intended to. No harm in taking advantage of it while it does! But because it's an undocumented, possibly-unintended feature, there's every possibility that a future update to the platform could "fix" the processing so that trick no longer works! I definitely plan to keep taking advantage of it for as long as it does work, though. (Again: lazy.) |
🤔 Just a thought - but perhaps the syntax checker (that is red-underlining the unexpected object when a string/number/boolean only was expected) is itself defective and the grammar is fine? |
@SlySven More than possible; Were GitHub to fix the checker so that it stops flagging those configs as syntax errors, that would certainly convey at least tacit support for using the matrix configs that way, and I know I'd be a lot more confident in assuming that I can rely on it and that it's not going to suddenly stop working in a future update. There's another thing they could do, though, to send that message even more clearly: document that syntax. My main concern so far isn't just that the syntax checker flags those configs. It's that the documentation contains no indication that the matrix is intended to be used that way, and the checker flags it which "might" be a sign that it's not. The documented functionality is ultimately a much more authoritative guide to what is and isn't officially supported. The syntax checker just provides some (very weak) hints as to what they might have intended, in the absence of officially documented support. |
(And, really, I think at this point they're stuck with supporting it whether they intended to or not, they'd break way too many workflows if they turned it off now.) |
So, I'm kind of banging my head against a wall with something, and I wanted to see if anyone has any clever solutions.
I have a project which builds in CMake, and the
cmake
commands are actually all the same whether running on Linux, macOS, or Windows. I've worked very hard to keep things that way, in fact, so that the build tooling could be as platform-agnostic as possible.So, I have a workflow written with build steps that are largely shared between all platforms in the matrix. (Each OS has its own dependency step, gated with an
if: ${{ runner.os == 'Linux' }}
(or'Windows'
or'macos'
), but that's the only non-shared config.)To differentiate the
-G
argument tocmake
, which selects the generator to use for the build system, I'm usingaction-cond
from @haya14busa which works great:The problem is, I can't think of any way to do the same thing for the MSYS2 shell. If I wanted to take advantage of the "Default shell" option from the README, I'd end up setting it as the default for every shell, including the ones that run on Linux and macOS, which obviously won't work! I've tried 100 different ways to conditionalize the setting, and they all failed:
if:
to thedefaults:
section of the config: Syntax errorhaya14busa/action-cond@v1
step that sets eithermsys2 {0}
orbash
, and useshell: ${{ steps.select_shell.outputs.value }}
in subsequent steps: Syntax error, apparently thesteps
object is not accessible from the metaconfiguration of subsequent steps.CC: ${{ matrix.compiler }}
:steps
before it's defined.)env
in every step that needs it:action-cond
into anoutputs
. Have the second jobneeds:
the first, and setshell: ${{ needs.job1.outputs.shell }}
on each step: Syntax error, it seems theneeds
context isn't any more accessible for defining steps than thesteps
context is.At this point I feel like I've exhausted all possibilities. Any suggestions, or do I really have to take my nice, cross-platform workflows and duplicate all of the run steps, just so I can get Windows to run them using the correct shell? 😞
The text was updated successfully, but these errors were encountered: