[PATCH v2 1/4] workflows: bootlinux: add reproducible builds support

Daniel Gomez
2025-09-19T12:25:40Z

Restructure bootlinux build parameters to use modular dictionary
approach for make module parameters and environment variables. This
prepares the codebase for extensible build features like ccache and
reproducible builds.

Add CONFIG_BOOTLINUX_REPRODUCIBLE_BUILDS option to enable deterministic
kernel builds by setting hardcoded environment variables. When enabled,
injects KBUILD_BUILD_TIMESTAMP='', KBUILD_BUILD_USER=kdevops, and
KBUILD_BUILD_HOST=kdevops during compilation.

Uses empty timestamp as recommended by LLVM documentation for optimal
compatibility with ccache and build reproducibility across different
development environments.

Features:
- Configurable via Kconfig with clear documentation
- Integrates with modular environment/params infrastructure
- Applied to both make module parameters and shell task environments
- Compatible with both GCC and Clang toolchains

Generated-by: Claude AI
Signed-off-by: Daniel Gomez <da.gomez@samsung.com>
---
playbooks/roles/bootlinux/defaults/main.yml | 26 ++++++++++++++
playbooks/roles/bootlinux/tasks/build/9p.yml | 44 +++++++++++++++++++++--
playbooks/roles/bootlinux/tasks/build/targets.yml | 6 ++--
playbooks/roles/bootlinux/tasks/main.yml | 22 ++++++++++--
workflows/linux/Kconfig | 17 +++++++++
5 files changed, 108 insertions(+), 7 deletions(-)

diff --git a/playbooks/roles/bootlinux/defaults/main.yml b/playbooks/roles/bootlinux/defaults/main.yml
index 84b61b8e..2d2eb798 100644
--- a/playbooks/roles/bootlinux/defaults/main.yml
+++ b/playbooks/roles/bootlinux/defaults/main.yml
@@ -30,7 +30,32 @@ make: "make"
# The commit is 34db57a47f875d11c4068567b9ec7ace174ec4cf
# introduce fact "ansible_processor_nproc": number of usable vcpus #66569
# https://github.com/ansible/ansible/pull/66569
+# Build command without environment variables (added via environment dict)
target_linux_make_cmd: "{{ make }} -j{{ ansible_processor_vcpus }}"
+
+# Make parameters dictionary for community.general.make module
+bootlinux_make_params: >-
+ {{
+ ({} | combine(
+ {
+ 'KBUILD_BUILD_TIMESTAMP': '',
+ 'KBUILD_BUILD_USER': 'kdevops',
+ 'KBUILD_BUILD_HOST': 'kdevops'
+ } if bootlinux_reproducible_builds|default(false)|bool else {}
+ ))
+ }}
+
+# Environment variables for remaining shell tasks (non-make)
+bootlinux_build_environment: >-
+ {{
+ ({} | combine(
+ {
+ 'KBUILD_BUILD_TIMESTAMP': '',
+ 'KBUILD_BUILD_USER': 'kdevops',
+ 'KBUILD_BUILD_HOST': 'kdevops'
+ } if bootlinux_reproducible_builds|default(false)|bool else {}
+ ))
+ }}
target_linux_make_install_cmd: "{{ target_linux_make_cmd }} modules_install install"

uninstall_kernel_enable: false
@@ -66,3 +91,4 @@ bootlinux_tree_custom_kernelrelease: false
bootlinux_tree_custom_localversion: false
bootlinux_is_dev_node: false
bootlinux_debug_ref: "{{ lookup('env', 'DEBUG_REF') | default(false, true) | bool }}"
+
diff --git a/playbooks/roles/bootlinux/tasks/build/9p.yml b/playbooks/roles/bootlinux/tasks/build/9p.yml
index acd69dc2..17b19cb3 100644
--- a/playbooks/roles/bootlinux/tasks/build/9p.yml
+++ b/playbooks/roles/bootlinux/tasks/build/9p.yml
@@ -135,6 +135,7 @@
register: configure_done
changed_when: configure_done.rc == 0 or configure_done.rc == 141
failed_when: configure_done.rc != 0 and configure_done.rc != 141
+ environment: "{{ bootlinux_build_environment }}"
args:
chdir: "{{ bootlinux_9p_host_path }}"
executable: /bin/bash
@@ -156,10 +157,44 @@
$ {{ ansible_callback_diy.result.output.cmd | join(' ') }}
{{ ansible_callback_diy.result.output.stdout | default('') }}

+- name: Debug kernel build command configuration for 9P build
+ ansible.builtin.debug:
+ msg: |
+ === KERNEL BUILD COMMAND DEBUG (9P BUILD) ===
+ build_jobs: {{ nproc_9p.stdout }}
+ bootlinux_make_params: {{ bootlinux_make_params }}
+ bootlinux_build_environment: {{ bootlinux_build_environment }}
+ bootlinux_compiler_clang: {{ bootlinux_compiler_clang|default(false) }}
+ bootlinux_reproducible_builds: {{ bootlinux_reproducible_builds|default(false) }}
+ run_once: true
+ delegate_to: localhost
+ vars:
+ ansible_callback_diy_runner_on_ok_msg: "{{ ansible_callback_diy.result.output.msg }}"
+ tags: ["build-linux"]
+
+- name: Test CC environment variable is working before build
+ ansible.builtin.shell: |
+ echo "CC environment test:"
+ echo "CC=${CC:-'not set'}"
+ echo "PATH=${PATH}"
+ which gcc || echo "gcc not found"
+ env | grep -E '^(CC|PATH)' | sort
+ environment: "{{ bootlinux_build_environment }}"
+ register: cc_test_result
+ run_once: true
+ delegate_to: localhost
+ vars:
+ ansible_callback_diy_runner_on_ok_msg: |
+ CC Environment Test Results:
+ {{ ansible_callback_diy.result.output.stdout | default('') }}
+ tags: ["build-linux"]
+
- name: Get kernelversion
community.general.make:
chdir: "{{ bootlinux_9p_host_path }}"
target: kernelversion
+ params: "{{ bootlinux_make_params }}"
+ environment: "{{ bootlinux_build_environment }}"
register: target_linux_kernelversion
tags: ["build-linux"]
when:
@@ -180,7 +215,8 @@
community.general.make:
jobs: "{{ nproc_9p.stdout }}"
chdir: "{{ bootlinux_9p_host_path }}"
- params: KERNELRELEASE={{ target_user_kernelrelease }}
+ params: "{{ bootlinux_make_params | combine({'KERNELRELEASE': target_user_kernelrelease}) }}"
+ environment: "{{ bootlinux_build_environment }}"
tags: ["build-linux"]
when:
- (active_linux_kernelrelease | default(target_linux_kernelrelease)) | length > 0
@@ -191,6 +227,8 @@
community.general.make:
jobs: "{{ nproc_9p.stdout }}"
chdir: "{{ bootlinux_9p_host_path }}"
+ params: "{{ bootlinux_make_params }}"
+ environment: "{{ bootlinux_build_environment }}"
tags: ["build-linux"]
when:
- (active_linux_kernelrelease | default(target_linux_kernelrelease)) | length == 0
@@ -201,8 +239,8 @@
community.general.make:
jobs: "{{ nproc_9p.stdout }}"
chdir: "{{ bootlinux_9p_host_path }}"
- params:
- M: "tools/testing/cxl"
+ params: "{{ bootlinux_make_params | combine({'M': 'tools/testing/cxl'}) }}"
+ environment: "{{ bootlinux_build_environment }}"
tags: ["build-linux", "cxl-build"]
when:
- bootlinux_cxl_test|bool
diff --git a/playbooks/roles/bootlinux/tasks/build/targets.yml b/playbooks/roles/bootlinux/tasks/build/targets.yml
index 6bd861cb..5deb330b 100644
--- a/playbooks/roles/bootlinux/tasks/build/targets.yml
+++ b/playbooks/roles/bootlinux/tasks/build/targets.yml
@@ -93,19 +93,21 @@
executable: /bin/bash

- name: Build {{ target_linux_tree }} on the target nodes
- ansible.builtin.command: "{{ target_linux_make_cmd }}"
+ ansible.builtin.shell: "{{ target_linux_make_cmd }}"
register: build
changed_when: "build.rc == 0"
args:
chdir: "{{ target_linux_dir_path }}"
+ environment: "{{ bootlinux_build_environment }}"
tags: ["build-linux"]

- name: Build {{ target_linux_tree }} cxl_test on the target nodes
- ansible.builtin.command: "{{ target_linux_make_cmd }} M=tools/testing/cxl"
+ ansible.builtin.shell: "{{ target_linux_make_cmd }} M=tools/testing/cxl"
register: build_cxl_test
changed_when: "build_cxl_test.rc == 0"
args:
chdir: "{{ target_linux_dir_path }}"
+ environment: "{{ bootlinux_build_environment }}"
tags: ["build-linux", "cxl-build"]
when:
- bootlinux_cxl_test|bool
diff --git a/playbooks/roles/bootlinux/tasks/main.yml b/playbooks/roles/bootlinux/tasks/main.yml
index e0eb2234..4110d596 100644
--- a/playbooks/roles/bootlinux/tasks/main.yml
+++ b/playbooks/roles/bootlinux/tasks/main.yml
@@ -193,6 +193,22 @@
when:
- bootlinux_9p|bool

+- name: Debug kernel build command configuration
+ ansible.builtin.debug:
+ msg: |
+ === KERNEL BUILD COMMAND DEBUG ===
+ build_jobs: {{ ansible_processor_vcpus }}
+ bootlinux_make_params: {{ bootlinux_make_params }}
+ bootlinux_build_environment: {{ bootlinux_build_environment }}
+ bootlinux_compiler_clang: {{ bootlinux_compiler_clang|default(false) }}
+ bootlinux_reproducible_builds: {{ bootlinux_reproducible_builds|default(false) }}
+ when:
+ - not workflow_linux_packaged|bool
+ - not bootlinux_9p|bool
+ vars:
+ ansible_callback_diy_runner_on_ok_msg: "{{ ansible_callback_diy.result.output.msg }}"
+ tags: ["install-linux", "debug"]
+
- name: Build the Linux kernel on the controller host
ansible.builtin.include_tasks:
file: "{{ role_path }}/tasks/build/9p.yml"
@@ -318,11 +334,12 @@
become: true
become_flags: "su - -c"
become_method: sudo
- ansible.builtin.command: "{{ target_linux_make_install_cmd }}"
+ ansible.builtin.shell: "{{ target_linux_make_install_cmd }}"
register: install_done
changed_when: "install_done.rc == 0"
args:
chdir: "{{ target_linux_dir_path }}"
+ environment: "{{ bootlinux_build_environment }}"
tags: ["install-linux"]
when:
- not workflow_linux_packaged|bool
@@ -335,11 +352,12 @@
become: true
become_flags: "su - -c"
become_method: sudo
- ansible.builtin.command: "{{ target_linux_make_install_cmd }} M=tools/testing/cxl INSTALL_MOD_DIR=updates"
+ ansible.builtin.shell: "{{ target_linux_make_install_cmd }} M=tools/testing/cxl INSTALL_MOD_DIR=updates"
register: install_done
changed_when: "install_done.rc == 0"
args:
chdir: "{{ target_linux_dir_path }}"
+ environment: "{{ bootlinux_build_environment }}"
tags: ["install-linux", "cxl-install"]
when:
- kdevops_workflow_enable_cxl|bool
diff --git a/workflows/linux/Kconfig b/workflows/linux/Kconfig
index 1b057042..897cb00f 100644
--- a/workflows/linux/Kconfig
+++ b/workflows/linux/Kconfig
@@ -171,6 +171,23 @@ config BOOTLINUX_COMPILER_CLANG

endchoice

+config BOOTLINUX_REPRODUCIBLE_BUILDS
+ bool "Enable reproducible builds"
+ output yaml
+ default n
+ help
+ Enable reproducible builds by setting deterministic environment
+ variables during kernel compilation. This ensures identical
+ binaries are produced from the same source code.
+
+ When enabled, sets:
+ - KBUILD_BUILD_TIMESTAMP='' (empty for deterministic timestamps)
+ - KBUILD_BUILD_USER='kdevops'
+ - KBUILD_BUILD_HOST='kdevops'
+
+ Recommended for CI/CD environments and when build reproducibility
+ is required. Compatible with both GCC and Clang toolchains.
+
choice
prompt "Type of development version of Linux to use"
default BOOTLINUX_LINUS if !BOOTLINUX_TREE_SET_BY_CLI && !BOOTLINUX_TREE_REF_SET_BY_CLI

--
2.50.1