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

Cross compile for Linux, MacOS and Windows on CI #2665

Merged
merged 20 commits into from
Jul 9, 2023

Conversation

owenthereal
Copy link
Member

@owenthereal owenthereal commented Jul 7, 2023

This PR includes the following changes:

This closes #2618 #2386

cc: @wader @itchyny

@owenthereal owenthereal changed the title Cross compile arm64 on Linux & MacOS Cross compile arm64 for Linux & MacOS on CI Jul 7, 2023
@@ -48,10 +49,15 @@ jobs:
--disable-maintainer-mode \
--disable-valgrind \
--with-oniguruma=builtin \
${{ matrix.configure_flag }}
--host=${{ matrix.arch }}-linux-gnu \
Copy link
Member

Choose a reason for hiding this comment

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

I started looking into doing cross builds yesterday but ended up reading old autoconf documentation about host, target and build and got irritated 😄 what a mess. Also a bit confused why jq's configure script only has --build and --host... and --host is what i would call "target"? :) it's generated by autoconf 2.71 which is quite modern.

Anyways thanks doing this!

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member Author

@owenthereal owenthereal Jul 9, 2023

Choose a reason for hiding this comment

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

I added cross-compilation for Windows as well. However, I noticed a few things:

  • Tests with the mingw-w64-x86_64 build failed for segmentation fault: (Maybe the same issue as the clang issue). I fallback to using msys gcc for x86_64 build
  • For Windows i386 build, I needed to add the __MINGW32__ guard to include <pthread.h> instead of the using pthread_* functions defined in jv.c & jv_thread.h due to "multiple definition" of the same functions (Ref).

make
strip jq
${ARCH}-linux-gnu-strip jq
file ./jq
Copy link
Member

Choose a reason for hiding this comment

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

Accidentally left in? i think it could make sense to keep

Copy link
Contributor

Choose a reason for hiding this comment

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

It's debugging, but it doesn't hurt.

Copy link
Member Author

Choose a reason for hiding this comment

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

The file line is to ensure the cross-compiled binary is what we expect. I guess it could be removed but it doesn't hurt to have that visibility.

.github/workflows/ci.yml Outdated Show resolved Hide resolved
.github/workflows/ci.yml Outdated Show resolved Hide resolved
@wader
Copy link
Member

wader commented Jul 7, 2023

A reason to wait for the docker job it make sure we notice if it fails

@wader
Copy link
Member

wader commented Jul 7, 2023

Should we try to not to mix arm64/aarch64 and x86_64/amd64? just use one?

@wader
Copy link
Member

wader commented Jul 7, 2023

ARM build for windows could be interesting but maybe for later?

@wader
Copy link
Member

wader commented Jul 7, 2023

Should we try to not to mix arm64/aarch64 and x86_64/amd64? just use one?

Sorry now i noticed this is already done in release step 👍

@itchyny itchyny added this to the 1.7 release milestone Jul 7, 2023
.github/workflows/ci.yml Outdated Show resolved Hide resolved
@@ -258,7 +269,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
needs: [linux, macos, windows, dist, docker]
needs: [linux, macos, windows, dist]
Copy link
Contributor

Choose a reason for hiding this comment

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

We should abort releasing if docker build/publish fails. Even if this change releases the artifact quickly, this isn't good.

Copy link
Member Author

Choose a reason for hiding this comment

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

To clarify, the release job creates a draft release instead of releasing it. However, I understand you want to wait for it before creating the draft release. I put it back, provided that you will improve the docker job speed by adopting @userdocs's suggestions.

.github/workflows/ci.yml Outdated Show resolved Hide resolved
@userdocs
Copy link

userdocs commented Jul 7, 2023

So I was looking at this closed pr #2652 and it seems apparent the obvious issue was that you are building via emulation, instead of cross compiling and then adding the prebuilt binary to the respective target arch, which would dramatically decrease the time to completion for that job. There is no real good reason to emulate the entire process and not on Github, you'd need to use something like https://buildjet.com/for-github-actions to make it faster.

Debian has these toolchains available https://packages.debian.org/source/bookworm/build-essential and when you use that to cross build you can do something like this perhaps?

Note: Using a debian docker (no need for ubuntu specifically here as they get these from Debian anyway and we are building statically)

https://github.com/userdocs/jq-cross-debian/actions/runs/5487472986 to publish binaries as release assets https://github.com/userdocs/jq-cross-debian/releases/tag/master-6944d81

And then just copy those to a docker image which will provide the same outcome at in a fraction of the time.

So now you have a full suite of cross built target arch static binaries as release assets people can download and then a very simple docker build process that takes simple copies the binary from the release asset or artifacts of the job.

In my example CI you can see the file outputs per build

https://github.com/userdocs/jq-cross-debian/actions/runs/5487472986/jobs/9998971987

For example,

amd64

jq-amd64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=6e8d99f61ae73fd3509778c6ff5a18076251c1a3, for GNU/Linux 3.2.0, stripped

s390x

jq-s390x: ELF 64-bit MSB executable, IBM S/390, version 1 (SYSV), statically linked, BuildID[sha1]=32615f38f2b33413a77bcd70432d87bbb87517c4, for GNU/Linux 3.2.0, stripped

Personally i'd do musl static but since you are already using a debian based solution and the binary appears to be be fullly static with no glibc dependency using crossbuild-essential works well, i think.

@itchyny
Copy link
Contributor

itchyny commented Jul 8, 2023

@userdocs Thank you. I'll improve the docker job to use the pre-built executables.

EDIT: I have fixed the docker job and it runs within 3 minutes to build the multi-platform image. What a big improvement.

cp artifacts/jq-linux-ubuntu-22.04-gcc-x86_64/jq release/jq-linux-amd64
cp artifacts/jq-linux-ubuntu-22.04-gcc-aarch64/jq release/jq-linux-arm64
cp artifacts/jq-macos-macos-13-clang-x86_64/jq release/jq-macos-amd64
cp artifacts/jq-macos-macos-13-clang-arm64/jq release/jq-macos-arm64
Copy link
Contributor

Choose a reason for hiding this comment

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

We can mv instead of cp here.

@owenthereal owenthereal changed the title Cross compile arm64 for Linux & MacOS on CI Cross compile arm64 for Linux, MacOS and Windows on CI Jul 9, 2023
@owenthereal
Copy link
Member Author

owenthereal commented Jul 9, 2023

Thanks @userdocs for the awesome example of cross-compiling on Linux with crossbuild-essential! I adopted your approach for the Linux build in this PR. I didn't change the docker job yet, considering @itchyny is going to. I imagine the docker job will copy the Linux artifacts from the linux job to a docker image.

Besides, I added cross-compliation for Windows. Now we have complete coverage of builds for most platforms 😄. The release job is also updated to upload all the artifacts. Here is an example.

Last but not least, we wouldn't need to explicitly strip and LDFLAGS=-s will also strip symbols.

This PR is ready to be reviewed again.

@userdocs
Copy link

userdocs commented Jul 9, 2023

@owenthereal glad it helped. I had used LDFLAGS since the configure appears to look for a non existent strip binaries and never find it, perhaps meaning the configure needs to be overhauled at some point. With the linker flags, the gcc doing the cross compiling will strip it using strip binary it comes with, so made sense as way around that.

and also for @itchyny, As for docker, after my post, I attempted to add a matrix multi platform (which would further increase speed) job but it's not quite working. Following this https://docs.docker.com/build/ci/github-actions/multi-platform/ it seems it need to merge the manifests in a following job.

I think a combination of the prebuilt binaries + matrixed docker multi platform job would be the fastest it could be.

But the matrix part of the docker/buildx job seems to be adding complexity and not sure what the actual benefit of that is yet.

@userdocs
Copy link

userdocs commented Jul 9, 2023

@owenthereal also, since you are using ubuntu they provide a riscv64 crossbuild that Debian does not.

https://packages.ubuntu.com/jammy/crossbuild-essential-riscv64

Since i used Debian i did not provide it but if you add it for ubuntu you used their full suite.

https://packages.ubuntu.com/search?suite=jammy&searchon=names&keywords=crossbuild-essential

      arch:
          [
            riscv64,
          ]
        include:
          - arch: riscv64
            CC: "riscv64-linux-gnu"

.github/workflows/ci.yml Outdated Show resolved Hide resolved
@owenthereal
Copy link
Member Author

@userdocs:

also, since you are using ubuntu they provide a riscv64 crossbuild that Debian does not.

Added riscv64 to the list. And build passed 😄

@owenthereal owenthereal changed the title Cross compile arm64 for Linux, MacOS and Windows on CI Cross compile for Linux, MacOS and Windows on CI Jul 9, 2023
Copy link
Contributor

@itchyny itchyny left a comment

Choose a reason for hiding this comment

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

Thank you!

@itchyny itchyny merged commit ce3701f into jqlang:master Jul 9, 2023
24 checks passed
@wader
Copy link
Member

wader commented Jul 9, 2023

Close #2386?

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