Dockerfile for development with cached repo and build artefacts

Hi all.

I’m trying to improve my Gnucash dev environment to use docker better, so that I can hack on Gnucash better :slight_smile:

Here’s my current Dockerfile attempt. Basically I want to cache the build artefacts, so that hacking->make doesn’t require compiling all files. Is this feasible within Docker?

# Stage 1: Build GnuCash and cache build artifacts
FROM ubuntu
WORKDIR /app
# Update the package lists and install build dependencies
RUN apt-get update && \
    apt-get install -y build-essential \
                       cmake \
                       libgtk2.0-dev \
                       libxml2-dev \
                       libxslt-dev \
                       guile-2.2-dev
RUN apt-get install -y libboost-all-dev \
                       libdbi-dev \
                       libdbd-sqlite3 \
                       libdbd-pgsql \
                       libaqbanking-dev \
                       gwenhywfar-tools \
                       libgoffice-0.10-dev \
                       libboost-dev
RUN apt-get install -y libboost-all-dev \
                       python3-dev \
                       libgnomecanvas2-dev \
                       guile-2.2-dev \
                       libgirepository1.0-dev \
                       libwebkit2gtk-4.0-dev \
                       libosp-dev
RUN apt-get install -y libboost-all-dev \
                       swig \
                       gtk-doc-tools \
                       docbook-xsl \
                       docbook-xml \
                       libsoup2.4-dev
RUN apt-get install -y libboost-all-dev \
                       libwebkit2gtk-4.0-dev \
                       libsecret-1-dev \
                       itstool \
                       gettext \
                       libwebkit2gtk-4.0-dev \
                       git \
                       zip
RUN apt-get install -y libofx-dev googletest

COPY . /app
RUN cd /app
RUN mkdir -p build && cd build && cmake -DWITH_AQBANKING=OFF .. && make -j4 && make install
# --mount=type=cache,target=./build,sharing=locked \

CMD ["/app/build/bin/gnucash"]

ENTRYPOINT ["/app/build/bin/gnucash"]

Wish to design the following: (In pseudo code)

“rebuild” stage

load dependencies
copy . /app (i.e. load repo)
cmake (i.e. create build dir - must be persistent)
make (compile build into executables - must be persistent)

“hacking” stage

copy build, executables from above
copy . /app (i.e. refresh repo)
make (efficient recompilation of changed source code only)
make install
copy installation files into folder outside container.

Thus I’d want to run “rebuild” once, then “hacking” during heavy development. Otherwise the COPY->CMAKE->MAKE stages would take 10mins. With the above pseudocode, modifying only 1-2 files would recompile only the changed files. Many thanks for considering!

I think I still don’t understand your goal, but I’m trying. Isn’t GnuCash requires Graphical interface? I noticed this in your Dockerfile

CMD ["/app/build/bin/gnucash"]

ENTRYPOINT ["/app/build/bin/gnucash"]

Do you really want to run the gnucash command in the container? Even if you want, you can’t set the same command as a CMD and as an ENTRYPOINT. If you are interested in more details, I recommend my blogpost about it: Constructing commands to run in Docker containers - DEV Community

You also have this in the Dockerfile

RUN cd /app

It does exactly nothing. Every RUN instruction starts a new container and nothing persists except what you save on the filesystem. IF you want to change directory, you need to use the WORKDIR instruction or move the cd to the same RUN instrcution in which you want to work in that directory, but you used WORKDIR at the beginning of the file.

If I ignore the CMD and ENTRYPOINT, I would assume you just want to build GNUCash and not run it in the container, and you just want to use the build cache of Docker to rebuild files only what you changed I may be wrong but wouldn’t make compile the whole /app directory?.

Ok maybe the CMD or ENTRYPOINT are incorrect – I"m still trying to set up a cacheable dockerised build. I am aware this violates the reproducibility characteristic of Docker – but it’ll be much faster to hack.

The idea is the following:

  1. set up environment (ubuntu), repo COPY . /app, dependencies install -y etc
  2. mkdir -p /app/build && cd /app/build && cmake -DCMAKE_INSTALL_PREFIX=/app/install .. – set up the persistent build dir
  3. make && make install to generate the build dir – the first run will be lengthy ie. 10mins
  4. pull out the compiled code from /app/install into host, run and test.
  5. use emacs outside container to hack on repo code, git commit, etc.
  6. rerun docker which will do redo 1, skip 2, go directly to 3. – the subsequent runs will be fast i.e. 3-4 seconds. – because the ‘make’ output will be persisted, i.e. still be in the build dir

Here’s my second attempt.

# Stage 1: Build GnuCash and cache build artifacts
FROM ubuntu
# Update the package lists and install build dependencies

RUN <<EOF
apt-get update && apt-get install -y build-essential cmake libgtk2.0-dev libxml2-dev libxslt-dev guile-3.0-dev \
 libboost-all-dev libdbi-dev libdbd-sqlite3 libdbd-pgsql libaqbanking-dev gwenhywfar-tools libgoffice-0.10-dev libboost-dev \
 python3-dev libgnomecanvas2-dev libgirepository1.0-dev libwebkit2gtk-4.0-dev libosp-dev \
 swig gtk-doc-tools docbook-xsl docbook-xml libsoup2.4-dev \
 libwebkit2gtk-4.0-dev libsecret-1-dev itstool gettext git zip \
 libofx-dev googletest
EOF

WORKDIR /app
COPY . /app/source
RUN cd /app
RUN mkdir -p build && cd build && cmake -DWITH_AQBANKING=OFF ../source -DCMAKE_INSTALL_PREFIX=/app/install

VOLUME /app/

CMD cd /app/build && make -j7 && make install

# --mount=type=cache,target=./build,sharing=locked \
# CMD ["/app/install/bin/gnucash"]

still doesn’t quite do what I want.