Hey all,
I’m looking for an efficient Dockerfile for CMake. For context, here’s Docker’s guide on making a Java based image: Build your Java image | Docker Docs
The main idea is to gather your dependencies before your source code is added, so that changes to your source code don’t un-necessarily cause you to fetch dependencies again.
# syntax=docker/dockerfile:1
FROM eclipse-temurin:17-jdk-jammy
WORKDIR /app
COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:resolve
COPY src ./src
CMD ["./mvnw", "spring-boot:run"]
For CMake, the same end goal isn’t straight forward. For context, I’ve tackled this problem with the following variables:
- I’m using FetchContent for dependencies, including usage of
OVERRIDE_FIND_PACKAGE
- I’m building with Ninja
- I’m using Cmake Presets
My attempt was to first make a CMakePresets.json like so:
{
"version": 6,
"configurePresets": [
{
"name": "ninja",
"generator": "Ninja Multi-Config",
"binaryDir": "ninja-build",
"cacheVariables": {
"CMAKE_UNITY_BUILD": "ON",
"CMAKE_INSTALL_MESSAGE": "LAZY",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"BUILD_SHARED_LIBS": "ON",
}
},
{
"name": "dependencies-only",
"inherits": "ninja",
"cacheVariables": {
"DEPENDENCIES_ONLY": "ON"
}
},
{
"name": "main-offline",
"inherits": "ninja",
"cacheVariables": {
"DEPENDENCIES_ONLY": "OFF",
"CMAKE_SKIP_INSTALL_ALL_DEPENDENCY": "ON",
"FETCHCONTENT_FULLY_DISCONNECTED": "ON",
"CMAKE_OPTIMIZE_DEPENDENCIES": "ON",
"CMAKE_LINK_DEPENDS_NO_SHARED": "ON"
}
}
],
"buildPresets": [
{
"name": "release",
"configurePreset": "ninja",
"configuration": "Release"
}
]
}
With a top-level CMakeLists.txt that has something like:
if(DEPENDENCIES_ONLY)
include(FetchDependencies)
else()
add_subdirectory(src)
endif()
I figured everything was in place, and I could do the following:
# Copy the minimum needed for build dependencies
COPY FetchDependencies.cmake CMakeLists.txt CMakePresets.json ./
# Download and build dependencies
RUN cmake --preset dependencies-only
RUN cmake --build --preset release
# Copy everything else
COPY . .
# Download and build the main project
RUN cmake --preset main-offline
RUN cmake --build --preset release --target main
However, it just doesn’t seem to work. I am seeing ninja rebuild everything on the last command in order to build main. I’ve read up on various topics about ninja rebuild issues, flags for build efficiency, etc, but I can’t get a working solution. Perhaps it’s the second configuration run, but I’m not really sure.
I feel like this should be a pretty standard, but I can’t find anything regarding it. Anyone out there with an idea for solving this problem?