orbstack / orbstack

Fast, light, simple Docker containers & Linux machines
https://orbstack.dev
MIT License
5.62k stars 44 forks source link

No such file or directory - Build error when using a host mounted volume #1393

Open niallnsec opened 3 months ago

niallnsec commented 3 months ago

Describe the bug

While attempting to compile a WASM version of Yara inside of a container, I think I have stumbled across an OrbStack bug.

When running a build with the build directory under the container filesystem everything completes successfully, however, if I run the build from a directory mounted from the host it fails with the error "No such file or directory" attempting to read a file which was just created. The file definitely exists. I am not sure how bests to gather debug info to validate whether it is caused by a bug in OrbStack or something else, but I have done my best to include everything needed to recreate the issue.

To Reproduce

  1. Build the emscripten docker image:

docker buildx build --pull --load -t registry.example.com/emscripten:stable .

Dockerfile ``` FROM ubuntu:noble AS builder ARG EMSCRIPTEN_VERSION=latest ENV EMSDK /emsdk RUN set -eux && \ apt-get -qq -y update && \ apt-get -qq install -y --no-install-recommends binutils build-essential ca-certificates file git \ python3 python3-pip curl cmake && \ mkdir -p "${EMSDK}" WORKDIR ${EMSDK} RUN set -eux && \ git clone https://github.com/emscripten-core/emsdk.git . && \ ./emsdk install ${EMSCRIPTEN_VERSION} && \ ./emsdk activate ${EMSCRIPTEN_VERSION} RUN set -eux && \ chmod 777 ${EMSDK}/upstream/emscripten && \ chmod -R 777 ${EMSDK}/upstream/emscripten/cache && \ echo "int main() { return 0; }" > hello.c && \ ${EMSDK}/upstream/emscripten/emcc -c hello.c && \ cat ${EMSDK}/upstream/emscripten/cache/sanity.txt RUN set -eux \ strip -s `which node` && \ rm -rf ${EMSDK}/upstream/emscripten/tests && \ rm -rf ${EMSDK}/upstream/emscripten/cache && \ mkdir ${EMSDK}/upstream/emscripten/cache && \ chmod -R 777 ${EMSDK}/upstream/emscripten/cache && \ rm -rf ${EMSDK}/.git && \ strip -s ${EMSDK}/upstream/bin/* FROM ubuntu:noble AS final COPY --from=builder /emsdk /emsdk COPY entrypoint.sh /usr/local/bin/entrypoint.sh ENV EMSDK /emsdk ENV PATH="${EMSDK}:${EMSDK}/upstream/emscripten:${EMSDK}/node/18.20.3_64bit/bin:${PATH}" RUN apt-get -qq -y update && \ apt-get -qq install -y --no-install-recommends \ sudo libxml2 ca-certificates python3 python3-pip wget curl zip unzip git git-lfs ssh-client \ build-essential make ant libidn12 cmake openjdk-11-jre-headless automake autoconf libtool \ pkg-config flex bison linux-headers-generic && \ chmod +x /usr/local/bin/entrypoint.sh && \ npm install -g typescript && \ apt-get -y clean && \ apt-get -y autoclean && \ apt-get -y autoremove && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /var/cache/debconf/*-old && \ rm -rf /usr/share/doc/* && \ rm -rf /usr/share/man/?? && \ rm -rf /usr/share/man/??_* USER nobody:nogroup WORKDIR /src ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] ```
entrypoint.sh ``` #!/bin/bash set -e EMSDK_QUIET=1 source "${EMSDK}/emsdk_env.sh" exec "$@" ```
  1. Extract the attached libyara-wasm library code. libyara-wasm.tar.gz

  2. Open a terminal in the extracted folder and start the docker build container

docker run --rm -it -v "$(pwd):/src" -u $(id -u):$(id -g) registry.example.com/emscripten:stable /bin/bash

  1. Inside the container, run the following to build the library:
mkdir build
cd build
emcmake cmake ..
emmake make -j8

The build should fail with the following error:

copying selected object files to avoid basename conflicts...
/emsdk/upstream/bin/llvm-ar: error: .libs/libyara.lax/lt1-la-hash.o: No such file or directory
make[4]: *** [Makefile:1583: libyara.la] Error 1
make[3]: *** [Makefile:1188: all] Error 2
make[2]: *** [CMakeFiles/yara.dir/build.make:86: yara-prefix/src/yara-stamp/yara-build] Error 2
make[1]: *** [CMakeFiles/Makefile2:113: CMakeFiles/yara.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
emmake: error: 'make -j8' failed (returned 2)
  1. While still in the container, run the following alternate build commands:
mkdir /tmp/build
cd /tmp/build
emcmake cmake /src
emmake make -j8

The build should complete successfully this time.

On the failed build, the file mentioned ".libs/libyara.lax/lt1-la-hash.o" does exist on disk when I check, and if you re-run the make command the build will resume and finish successfully. Since the error only occurs when build files are on a host mounted volume, it seems like there could be some kind of race condition at play.

Expected behavior

Both builds should complete successfully, regardless of the location of the build directory.

Diagnostic report (REQUIRED)

OrbStack info: Version: 1.7.0-rc2 Commit: 286173a3053ed7fcc0784d31ef8791886ad60224 (v1.7.0-rc2)

System info: macOS: 14.6.1 (23G93) CPU: arm64, 16 cores CPU model: Apple M3 Max Model: Mac15,9 Memory: 48 GiB

Full report: https://orbstack.dev/_admin/diag/orbstack-diagreport_2024-08-20T21-30-30.670595Z.zip

Screenshots and additional context (optional)

No response

bryanforbes commented 2 months ago

I've run into a similar issue using buildroot with bind mounts. Some libraries/projects instruct libtool to make hard links to build files in a temporary directory before it links the entire project from that temporary directory and that seems to trip up OrbStack. If I reduce the CPU limit to 100% (1 core) and build those libraries individually after the build fails, then increase the CPU limit back to 800% (8 cores) and restart the build, everything works fine. I'm also under the impression that there's a race condition somewhere.

Reproduction steps:

  1. Ensure OrbStack is configured with a CPU limit of 200% or more (I recommend 800%)
  2. git clone https://github.com/bryanforbes/batocera.linux.git
  3. cd batocera.linux
  4. git checkout origin/bryanforbes/macos-build
  5. git submodule update --init
  6. make build-docker-image
  7. echo 'EXTRA_OPTS := BR2_CCACHE_INITIAL_SETUP=\"--max-size=50G\"' > batocera.mk
  8. make x86_64-build

The build will fail at util-linux-libs, util-linux, or gmp with a message similar to the following:

/x86_64/host/lib/gcc/x86_64-buildroot-linux-gnu/13.3.0/../../../../x86_64-buildroot-linux-gnu/bin/ar: .libs/libgmp.lax/lt2-add.o: No such file or directory
make[3]: *** [Makefile:883: libgmp.la] Error 1
make[3]: Leaving directory '/x86_64/build/gmp-6.3.0'
make[2]: *** [Makefile:998: all-recursive] Error 1
make[2]: Leaving directory '/x86_64/build/gmp-6.3.0'
make[1]: *** [Makefile:788: all] Error 2
make[1]: Leaving directory '/x86_64/build/gmp-6.3.0'
make: *** [package/pkg-generic.mk:283: /x86_64/build/gmp-6.3.0/.stamp_built] Error 2
make: Leaving directory '/build/buildroot'
make: *** [x86_64-build] Error 2

To get around this issue, when the build fails, I reduce the CPU limit to 100% and run make x86_64-pkg PKG=<package name here>, wait for it to finish, increase the limit to 800%, and re-run make x86_64-build.

houaq commented 1 month ago

Got same issue while building openwrt, waiting for solution...

niallnsec commented 1 month ago

@houaq Something that may help you until this is fixed is to run the make command twice. I know this will be specific to how the openwrt makefile is written so I am not sure if it will work, but for me, when I am building my libyara-wasm package I have put in a workaround to run make and then after it fails with an error, run it again. The second time it works since all the files are actually built correctly from the previous run and it just continues where it left off previously and builds the library as it should. Like I said, it may not work since it will depend on the individual makefiles but its worth a try if this is blocking you.

houaq commented 1 month ago

@niallnsec Thanks for the quick reply! I also did this, it may work after 2 or 3 tries, but not sure :(