Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,72 @@ jobs:
${SCCACHE_PATH} --show-stats
${SCCACHE_PATH} --show-stats | grep -e "Cache hits\s*[1-9]"

cmake-modules:
runs-on: ubuntu-24.04
needs: build

env:
SCCACHE_GHA_ENABLED: "on"
LLVM_VERSION: "19"

steps:
- uses: actions/checkout@v5

- name: Configure Cache Env
uses: actions/github-script@v8
with:
script: |
core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '')

- uses: actions/download-artifact@v5
with:
name: integration-tests
path: /home/runner/.cargo/bin/
- name: Chmod for binary
run: chmod +x ${SCCACHE_PATH}

- name: Install dependencies
shell: bash
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh "${LLVM_VERSION}"
sudo apt-get update
sudo apt-get install -y ninja-build
pip install cmake

- name: Test
run: |
cd `pwd`/tests/cmake-modules/
cmake -B build -G Ninja \
-DCMAKE_C_COMPILER=clang-${LLVM_VERSION} \
-DCMAKE_CXX_COMPILER=clang++-${LLVM_VERSION} \
-DCMAKE_C_COMPILER_LAUNCHER=${SCCACHE_PATH} \
-DCMAKE_CXX_COMPILER_LAUNCHER=${SCCACHE_PATH}
cmake --build build

- name: Output
run: |
${SCCACHE_PATH} --show-stats

- name: Test Twice for Cache Read
run: |
cd `pwd`/tests/cmake-modules/
rm -rf build
cmake -B build -G Ninja \
-DCMAKE_C_COMPILER=clang-${LLVM_VERSION} \
-DCMAKE_CXX_COMPILER=clang++-${LLVM_VERSION} \
-DCMAKE_C_COMPILER_LAUNCHER=${SCCACHE_PATH} \
-DCMAKE_CXX_COMPILER_LAUNCHER=${SCCACHE_PATH}
cmake --build build

- name: Output
run: |
${SCCACHE_PATH} --show-stats

${SCCACHE_PATH} --show-stats | grep -e "Cache hits\s*[1-9]"

xcode:
runs-on: macos-latest
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ tests/**/Cargo.lock

.direnv/
result
.vscode/settings.json
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,22 @@ Known Caveats

[More details on Rust caveats](/docs/Rust.md)

### C++20 Modules

sccache has partial support for C++20 named modules when using **Clang**. The following flags are supported:

* `-fmodule-file=<path>` and `-fmodule-file=<name>=<path>` - importing precompiled module interfaces
* `-fmodule-output=<path>` - generating module interface output alongside object files
* `--precompile` - compiling module interface units
* `-fmodules-reduced-bmi` - generating reduced BMI files

The following module-related flags are **not supported** and will bypass the cache:

* `-fmodules` and `-fcxx-modules` - Clang header modules (not C++20 named modules)
* `-fprebuilt-implicit-modules` and `-fprebuilt-module-path` - implicit module discovery

**GCC** and **MSVC** C++20 modules are not yet supported. Compilations using `-fmodules-ts` (GCC) or `/interface`, `/ifcOutput`, etc. (MSVC) will bypass the cache.

### User Agent

* Requests sent to your storage option of choice will have a user agent header indicating the current sccache version, e.g. `sccache/0.8.2`.
Expand Down
198 changes: 197 additions & 1 deletion src/compiler/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ counted_array!(pub static ARGS: [ArgInfo<gcc::ArgData>; _] = [
take_arg!("--dependent-lib", OsString, Concatenated(b'='), PassThrough),
take_arg!("--hip-device-lib-path", PathBuf, Concatenated(b'='), PassThroughPath),
take_arg!("--hip-path", PathBuf, Concatenated(b'='), PassThroughPath),
flag!("--precompile", ModuleOnlyFlag),
take_arg!("--rocm-path", PathBuf, Concatenated(b'='), PassThroughPath),
take_arg!("--serialize-diagnostics", OsString, Separated, PassThrough),
take_arg!("--target", OsString, Separated, PassThrough),
Expand All @@ -207,12 +208,16 @@ counted_array!(pub static ARGS: [ArgInfo<gcc::ArgData>; _] = [
take_arg!("-fdebug-compilation-dir", OsString, Separated, PassThrough),
take_arg!("-fembed-offload-object", PathBuf, Concatenated(b'='), ExtraHashFile),
take_arg!("-fexperimental-assignment-tracking", OsString, Concatenated(b'='), PassThrough),
flag!("-fmodules", TooHardFlag),
take_arg!("-fmodule-file", OsString, Concatenated(b'='), ExtraHashFileClangModuleFile),
take_arg!("-fmodule-output", OsString, Concatenated, ClangModuleOutput),
flag!("-fmodules-reduced-bmi", PassThroughFlag),
flag!("-fno-color-diagnostics", NoDiagnosticsColorFlag),
flag!("-fno-pch-timestamp", PassThroughFlag),
flag!("-fno-profile-instr-generate", TooHardFlag),
flag!("-fno-profile-instr-use", TooHardFlag),
take_arg!("-fplugin", PathBuf, CanBeConcatenated(b'='), ExtraHashFile),
flag!("-fprebuilt-implicit-modules", TooHardFlag),
take_arg!("-fprebuilt-module-path", OsString, Concatenated, TooHard),
flag!("-fprofile-instr-generate", ProfileGenerate),
// Note: the PathBuf argument is optional
take_arg!("-fprofile-instr-use", PathBuf, Concatenated(b'='), ClangProfileUse),
Expand Down Expand Up @@ -1130,6 +1135,197 @@ mod test {
);
}

#[test]
fn test_parse_arguments_cxx20_modules_unsupported() {
// -fprebuilt-implicit-modules is not supported (implicit module discovery)
assert_eq!(
CompilerArguments::CannotCache("-fprebuilt-implicit-modules", None),
parse_arguments_(stringvec![
"-c",
"foo.c",
"-fprebuilt-implicit-modules",
"-o",
"foo.o"
])
);

// -fprebuilt-module-path is not supported (implicit module path discovery)
assert_eq!(
CompilerArguments::CannotCache("-fprebuilt-module-path", None),
parse_arguments_(stringvec![
"-c",
"foo.c",
"-fprebuilt-module-path=/path/to/modules",
"-o",
"foo.o"
])
);
}

#[test]
fn test_parse_arguments_cxx20_module_precompile() {
// Test --precompile flag for creating module interface units
let a = parses!(
"-c",
"module.cppm",
"-o",
"module.pcm",
"--precompile",
"-x",
"c++-module"
);
assert_eq!(Some("module.cppm"), a.input.to_str());
assert_eq!(Language::CxxModule, a.language);
assert_map_contains!(
a.outputs,
(
"obj",
ArtifactDescriptor {
path: PathBuf::from("module.pcm"),
optional: false
}
)
);
}

#[test]
fn test_parse_arguments_cxx20_module_fmodule_file() {
// Test -fmodule-file= for importing precompiled modules
let a = parses!("-c", "foo.cpp", "-o", "foo.o", "-fmodule-file=mymodule.pcm");
assert_eq!(Some("foo.cpp"), a.input.to_str());
assert_eq!(ovec!["-fmodule-file=mymodule.pcm"], a.common_args);
assert_eq!(
ovec![std::env::current_dir().unwrap().join("mymodule.pcm")],
a.extra_hash_files
);
}

#[test]
fn test_parse_arguments_cxx20_module_fmodule_file_with_name() {
// Test -fmodule-file=name=path syntax
let a = parses!(
"-c",
"foo.cpp",
"-o",
"foo.o",
"-fmodule-file=mymodule=path/to/mymodule.pcm"
);
assert_eq!(Some("foo.cpp"), a.input.to_str());
assert_eq!(
ovec!["-fmodule-file=mymodule=path/to/mymodule.pcm"],
a.common_args
);
assert_eq!(
ovec![
std::env::current_dir()
.unwrap()
.join("path/to/mymodule.pcm")
],
a.extra_hash_files
);
}

#[test]
fn test_parse_arguments_cxx20_module_fmodule_output() {
// Test -fmodule-output= for generating module output alongside object file
let a = parses!(
"-c",
"module.cppm",
"-o",
"module.o",
"-fmodule-output=module.pcm"
);
assert_eq!(Some("module.cppm"), a.input.to_str());
assert_map_contains!(
a.outputs,
(
"obj",
ArtifactDescriptor {
path: PathBuf::from("module.o"),
optional: false
}
),
(
"module",
ArtifactDescriptor {
path: PathBuf::from("module.pcm"),
optional: false
}
)
);
assert_eq!(ovec!["-fmodule-output=module.pcm"], a.common_args);
}

#[test]
fn test_parse_arguments_cxx20_module_fmodule_output_implicit_path() {
// Test -fmodule-output without explicit path (uses input name + .pcm)
let a = parses!("-c", "mymodule.cppm", "-o", "mymodule.o", "-fmodule-output");
assert_eq!(Some("mymodule.cppm"), a.input.to_str());
assert_map_contains!(
a.outputs,
(
"obj",
ArtifactDescriptor {
path: PathBuf::from("mymodule.o"),
optional: false
}
),
(
"module",
ArtifactDescriptor {
path: PathBuf::from("mymodule.cppm.pcm"),
optional: false
}
)
);
}

#[test]
fn test_parse_arguments_cxx20_module_fmodules_reduced_bmi() {
// Test -fmodules-reduced-bmi flag (Clang 18+)
let a = parses!(
"-c",
"module.cppm",
"-o",
"module.o",
"-fmodule-output=module.pcm",
"-fmodules-reduced-bmi"
);
assert_eq!(Some("module.cppm"), a.input.to_str());
assert_eq!(
ovec!["-fmodule-output=module.pcm", "-fmodules-reduced-bmi"],
a.common_args
);
}

#[test]
fn test_parse_arguments_cxx20_module_combined_flags() {
// Test combination of module flags as typically used in practice
let a = parses!(
"-c",
"consumer.cpp",
"-o",
"consumer.o",
"-fmodule-file=mymodule=mymodule.pcm",
"-fmodule-file=othermodule=other.pcm"
);
assert_eq!(Some("consumer.cpp"), a.input.to_str());
assert_eq!(
ovec![
"-fmodule-file=mymodule=mymodule.pcm",
"-fmodule-file=othermodule=other.pcm"
],
a.common_args
);
assert_eq!(
vec![
std::env::current_dir().unwrap().join("mymodule.pcm"),
std::env::current_dir().unwrap().join("other.pcm"),
],
a.extra_hash_files
);
}

#[test]
fn test_compile_clang_cuda_does_not_dist_compile() {
let creator = new_creator();
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ pub enum Language {
Cubin,
Rust,
Hip,
CxxModule,
}

impl Language {
Expand All @@ -259,6 +260,7 @@ impl Language {
Some("ii") => Some(Language::CxxPreprocessed),
Some("H") | Some("hh") | Some("hp") | Some("hpp") | Some("HPP") | Some("hxx")
| Some("h++") | Some("tcc") => Some(Language::CxxHeader),
Some("cppm") | Some("ixx") => Some(Language::CxxModule),
Some("m") => Some(Language::ObjectiveC),
Some("mi") => Some(Language::ObjectiveCPreprocessed),
Some("M") | Some("mm") => Some(Language::ObjectiveCxx),
Expand Down Expand Up @@ -297,6 +299,7 @@ impl Language {
Language::Cubin => "cubin",
Language::Rust => "rust",
Language::Hip => "hip",
Language::CxxModule => "c++-module",
}
}

Expand Down Expand Up @@ -358,6 +361,7 @@ impl Language {
Language::Rust => None, // Let the compiler decide
Language::Hip => Some("hip"),
Language::GenericHeader => None, // Let the compiler decide
Language::CxxModule => Some("c++-module"),
}
}

Expand All @@ -383,6 +387,7 @@ impl CompilerKind {
| Language::CPreprocessed
| Language::Cxx
| Language::CxxHeader
| Language::CxxModule
| Language::CxxPreprocessed
| Language::GenericHeader
| Language::ObjectiveC
Expand Down
Loading
Loading