C++: Make it possible to split up the C++ code generated for a .slint file

Add a COMPILATION_UNITS argument to slint_target_sources that defines into how many .cpp files to split up a .slint file. The new default is now one.
This commit is contained in:
Simon Hausmann 2024-08-18 15:04:50 +02:00 committed by Simon Hausmann
parent 12f5343cd8
commit c25a03d6f7
6 changed files with 160 additions and 31 deletions

View file

@ -12,7 +12,7 @@ set_property(CACHE DEFAULT_SLINT_EMBED_RESOURCES PROPERTY STRINGS
function(SLINT_TARGET_SOURCES target) function(SLINT_TARGET_SOURCES target)
# Parse the NAMESPACE argument # Parse the NAMESPACE argument
cmake_parse_arguments(SLINT_TARGET_SOURCES "" "NAMESPACE" "LIBRARY_PATHS" ${ARGN}) cmake_parse_arguments(SLINT_TARGET_SOURCES "" "NAMESPACE;COMPILATION_UNITS" "LIBRARY_PATHS" ${ARGN})
get_target_property(enabled_features Slint::Slint SLINT_ENABLED_FEATURES) get_target_property(enabled_features Slint::Slint SLINT_ENABLED_FEATURES)
if (("EXPERIMENTAL" IN_LIST enabled_features) AND ("SYSTEM_TESTING" IN_LIST enabled_features)) if (("EXPERIMENTAL" IN_LIST enabled_features) AND ("SYSTEM_TESTING" IN_LIST enabled_features))
@ -30,6 +30,15 @@ function(SLINT_TARGET_SOURCES target)
set(_SLINT_CPP_NAMESPACE_ARG "--cpp-namespace=${SLINT_TARGET_SOURCES_NAMESPACE}") set(_SLINT_CPP_NAMESPACE_ARG "--cpp-namespace=${SLINT_TARGET_SOURCES_NAMESPACE}")
endif() endif()
if (DEFINED SLINT_TARGET_SOURCES_COMPILATION_UNITS)
if (NOT SLINT_TARGET_SOURCES_COMPILATION_UNITS MATCHES "^[0-9]+$")
message(FATAL_ERROR "Expected number, got '${SLINT_TARGET_SOURCES_COMPILATION_UNITS}' for COMPILATION_UNITS argument")
endif()
set(compilation_units ${SLINT_TARGET_SOURCES_COMPILATION_UNITS})
else()
set(compilation_units 1)
endif()
while (SLINT_TARGET_SOURCES_LIBRARY_PATHS) while (SLINT_TARGET_SOURCES_LIBRARY_PATHS)
list(POP_FRONT SLINT_TARGET_SOURCES_LIBRARY_PATHS name_and_path) list(POP_FRONT SLINT_TARGET_SOURCES_LIBRARY_PATHS name_and_path)
list(APPEND _SLINT_CPP_LIBRARY_PATHS_ARG "-L") list(APPEND _SLINT_CPP_LIBRARY_PATHS_ARG "-L")
@ -48,8 +57,15 @@ function(SLINT_TARGET_SOURCES target)
set(scale_factor_target_prop "$<TARGET_PROPERTY:${target},SLINT_SCALE_FACTOR>") set(scale_factor_target_prop "$<TARGET_PROPERTY:${target},SLINT_SCALE_FACTOR>")
set(scale_factor_arg "$<IF:$<STREQUAL:${scale_factor_target_prop},>,,--scale-factor=${scale_factor_target_prop}>") set(scale_factor_arg "$<IF:$<STREQUAL:${scale_factor_target_prop},>,,--scale-factor=${scale_factor_target_prop}>")
if (compilation_units GREATER 0)
foreach(cpp_num RANGE 1 ${compilation_units})
list(APPEND cpp_files "${CMAKE_CURRENT_BINARY_DIR}/slint_generated_${_SLINT_BASE_NAME}_${cpp_num}.cpp")
endforeach()
list(TRANSFORM cpp_files PREPEND "--cpp-file=" OUTPUT_VARIABLE cpp_files_arg)
endif()
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.h OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.h ${cpp_files}
COMMAND ${SLINT_COMPILER_ENV} $<TARGET_FILE:Slint::slint-compiler> ${_SLINT_ABSOLUTE} COMMAND ${SLINT_COMPILER_ENV} $<TARGET_FILE:Slint::slint-compiler> ${_SLINT_ABSOLUTE}
-o ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.h -o ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.h
--depfile ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.d --depfile ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.d
@ -59,13 +75,14 @@ function(SLINT_TARGET_SOURCES target)
${_SLINT_CPP_NAMESPACE_ARG} ${_SLINT_CPP_NAMESPACE_ARG}
${_SLINT_CPP_LIBRARY_PATHS_ARG} ${_SLINT_CPP_LIBRARY_PATHS_ARG}
${scale_factor_arg} ${scale_factor_arg}
${cpp_files_arg}
DEPENDS Slint::slint-compiler ${_SLINT_ABSOLUTE} DEPENDS Slint::slint-compiler ${_SLINT_ABSOLUTE}
COMMENT "Generating ${_SLINT_BASE_NAME}.h" COMMENT "Generating ${_SLINT_BASE_NAME}.h"
DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.d DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.d
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
) )
target_sources(${target} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.h) target_sources(${target} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.h ${cpp_files})
endforeach() endforeach()
target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
endfunction() endfunction()

View file

@ -5,7 +5,7 @@
## `slint_target_sources` ## `slint_target_sources`
``` ```
slint_target_sources(<target> <files>.... [NAMESPACE namespace] [LIBRARY_PATHS name1=lib1 name2=lib2 ...]) slint_target_sources(<target> <files>.... [NAMESPACE namespace] [LIBRARY_PATHS name1=lib1 name2=lib2 ...] [COMPILATION_UNITS num])
``` ```
Use this function to tell cmake about the .slint files of your application, similar to the builtin cmake [target_sources](https://cmake.org/cmake/help/latest/command/target_sources.html) function. Use this function to tell cmake about the .slint files of your application, similar to the builtin cmake [target_sources](https://cmake.org/cmake/help/latest/command/target_sources.html) function.
@ -31,6 +31,11 @@ slint_target_sources(my_application the_window.slint
) )
``` ```
By default, a `.slint` file is compiled to a `.h` file for inclusion in your application's business logic code, and a `.cpp` file with code generated by
the slint-compier. If you want to speed up compilation of the generated `.cpp` file, then you can pass the `COMPILATION_UNITS` argument with a value greater
than 1 to create multiple `.cpp` files. These can be compiled in parallel, which might speed up overall build times. However, splitting the generated code
across multiple `.cpp` files decreases the compiler's visibility and thus ability to perform optimizations. You can also pass `COMPILATION_UNITS 0` to generate
only one single `.h` file.
## Resource Embedding ## Resource Embedding

View file

@ -74,7 +74,7 @@ pub fn generate(
match format { match format {
#[cfg(feature = "cpp")] #[cfg(feature = "cpp")]
OutputFormat::Cpp(config) => { OutputFormat::Cpp(config) => {
let output = cpp::generate(doc, config, compiler_config); let output = cpp::generate(doc, config, compiler_config)?;
write!(destination, "{}", output)?; write!(destination, "{}", output)?;
} }
#[cfg(feature = "rust")] #[cfg(feature = "rust")]

View file

@ -7,6 +7,7 @@
// cSpell:ignore cmath constexpr cstdlib decltype intptr itertools nullptr prepended struc subcomponent uintptr vals // cSpell:ignore cmath constexpr cstdlib decltype intptr itertools nullptr prepended struc subcomponent uintptr vals
use std::fmt::Write; use std::fmt::Write;
use std::io::BufWriter;
use lyon_path::geom::euclid::approxeq::ApproxEq; use lyon_path::geom::euclid::approxeq::ApproxEq;
@ -14,6 +15,8 @@ use lyon_path::geom::euclid::approxeq::ApproxEq;
#[derive(Clone, Debug, Default, PartialEq)] #[derive(Clone, Debug, Default, PartialEq)]
pub struct Config { pub struct Config {
pub namespace: Option<String>, pub namespace: Option<String>,
pub cpp_files: Vec<std::path::PathBuf>,
pub header_include: String,
} }
fn ident(ident: &str) -> String { fn ident(ident: &str) -> String {
@ -82,6 +85,7 @@ mod cpp_ast {
///A full C++ file ///A full C++ file
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct File { pub struct File {
pub is_cpp_file: bool,
pub includes: Vec<String>, pub includes: Vec<String>,
pub after_includes: String, pub after_includes: String,
pub namespace: Option<String>, pub namespace: Option<String>,
@ -89,10 +93,65 @@ mod cpp_ast {
pub definitions: Vec<Declaration>, pub definitions: Vec<Declaration>,
} }
impl File {
pub fn split_off_cpp_files(&mut self, header_file_name: String, count: usize) -> Vec<File> {
let mut cpp_files = Vec::with_capacity(count);
if count == 0 {
return cpp_files;
}
let mut definitions = Vec::new();
let mut i = 0;
while i < self.definitions.len() {
if matches!(&self.definitions[i], Declaration::Function(fun) if fun.template_parameters.is_some())
{
i += 1;
continue;
}
definitions.push(self.definitions.remove(i));
}
// Any definition in the header file is inline.
self.definitions.iter_mut().for_each(|def| match def {
Declaration::Function(f) => f.is_inline = true,
Declaration::Var(v) => v.is_inline = true,
_ => {}
});
let cpp_includes = vec![format!("\"{header_file_name}\"")];
let chunk_size = definitions.len() / count;
cpp_files.extend((0..count - 1).map(|_| File {
is_cpp_file: true,
includes: cpp_includes.clone(),
after_includes: String::new(),
namespace: self.namespace.clone(),
declarations: Default::default(),
definitions: definitions.drain(0..chunk_size).collect(),
}));
cpp_files.push(File {
is_cpp_file: true,
includes: cpp_includes,
after_includes: String::new(),
namespace: self.namespace.clone(),
declarations: Default::default(),
definitions,
});
cpp_files.resize_with(count, Default::default);
cpp_files
}
}
impl Display for File { impl Display for File {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
writeln!(f, "// This file is auto-generated")?; writeln!(f, "// This file is auto-generated")?;
writeln!(f, "#pragma once")?; if !self.is_cpp_file {
writeln!(f, "#pragma once")?;
}
for i in &self.includes { for i in &self.includes {
writeln!(f, "#include {}", i)?; writeln!(f, "#include {}", i)?;
} }
@ -186,6 +245,7 @@ mod cpp_ast {
statements: f.statements.take(), statements: f.statements.take(),
template_parameters: f.template_parameters.clone(), template_parameters: f.template_parameters.clone(),
constructor_member_initializers: f.constructor_member_initializers.clone(), constructor_member_initializers: f.constructor_member_initializers.clone(),
..Default::default()
})) }))
} }
_ => None, _ => None,
@ -223,6 +283,7 @@ mod cpp_ast {
pub is_constructor_or_destructor: bool, pub is_constructor_or_destructor: bool,
pub is_static: bool, pub is_static: bool,
pub is_friend: bool, pub is_friend: bool,
pub is_inline: bool,
/// The list of statement instead the function. When None, this is just a function /// The list of statement instead the function. When None, this is just a function
/// declaration without the definition /// declaration without the definition
pub statements: Option<Vec<String>>, pub statements: Option<Vec<String>>,
@ -244,8 +305,9 @@ mod cpp_ast {
if self.is_friend { if self.is_friend {
write!(f, "friend ")?; write!(f, "friend ")?;
} }
// all functions are `inline` because we are in a header if self.is_inline {
write!(f, "inline ")?; write!(f, "inline ")?;
}
if !self.is_constructor_or_destructor { if !self.is_constructor_or_destructor {
write!(f, "auto ")?; write!(f, "auto ")?;
} }
@ -270,6 +332,7 @@ mod cpp_ast {
/// A variable or a member declaration. /// A variable or a member declaration.
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Var { pub struct Var {
pub is_inline: bool,
pub ty: String, pub ty: String,
pub name: String, pub name: String,
pub array_size: Option<usize>, pub array_size: Option<usize>,
@ -541,7 +604,7 @@ pub fn generate(
doc: &Document, doc: &Document,
config: Config, config: Config,
compiler_config: &CompilerConfiguration, compiler_config: &CompilerConfiguration,
) -> impl std::fmt::Display { ) -> std::io::Result<impl std::fmt::Display> {
let mut file = File { namespace: config.namespace.clone(), ..Default::default() }; let mut file = File { namespace: config.namespace.clone(), ..Default::default() };
file.includes.push("<array>".into()); file.includes.push("<array>".into());
@ -570,10 +633,11 @@ pub fn generate(
init.push('}'); init.push('}');
file.declarations.push(Declaration::Var(Var { file.declarations.push(Declaration::Var(Var {
ty: "const inline uint8_t".into(), ty: "const uint8_t".into(),
name: format!("slint_embedded_resource_{}", er.id), name: format!("slint_embedded_resource_{}", er.id),
array_size: Some(data.len()), array_size: Some(data.len()),
init: Some(init), init: Some(init),
..Default::default()
})); }));
} }
#[cfg(feature = "software-renderer")] #[cfg(feature = "software-renderer")]
@ -601,14 +665,15 @@ pub fn generate(
let data = data.iter().map(ToString::to_string).join(", "); let data = data.iter().map(ToString::to_string).join(", ");
let data_name = format!("slint_embedded_resource_{}_data", er.id); let data_name = format!("slint_embedded_resource_{}_data", er.id);
file.declarations.push(Declaration::Var(Var { file.declarations.push(Declaration::Var(Var {
ty: "inline const uint8_t".into(), ty: "const uint8_t".into(),
name: data_name.clone(), name: data_name.clone(),
array_size: Some(count), array_size: Some(count),
init: Some(format!("{{ {data} }}")), init: Some(format!("{{ {data} }}")),
..Default::default()
})); }));
let texture_name = format!("slint_embedded_resource_{}_texture", er.id); let texture_name = format!("slint_embedded_resource_{}_texture", er.id);
file.declarations.push(Declaration::Var(Var { file.declarations.push(Declaration::Var(Var {
ty: "inline const slint::cbindgen_private::types::StaticTexture".into(), ty: "const slint::cbindgen_private::types::StaticTexture".into(),
name: texture_name.clone(), name: texture_name.clone(),
array_size: None, array_size: None,
init: Some(format!( init: Some(format!(
@ -619,6 +684,7 @@ pub fn generate(
.index = 0, .index = 0,
}}" }}"
)), )),
..Default::default()
})); }));
let init = format!("slint::cbindgen_private::types::StaticTextures {{ let init = format!("slint::cbindgen_private::types::StaticTextures {{
.size = {{ {width}, {height} }}, .size = {{ {width}, {height} }},
@ -627,10 +693,11 @@ pub fn generate(
.textures = slint::cbindgen_private::Slice<slint::cbindgen_private::types::StaticTexture>{{ &{texture_name}, 1 }} .textures = slint::cbindgen_private::Slice<slint::cbindgen_private::types::StaticTexture>{{ &{texture_name}, 1 }}
}}"); }}");
file.declarations.push(Declaration::Var(Var { file.declarations.push(Declaration::Var(Var {
ty: "inline const slint::cbindgen_private::types::StaticTextures".into(), ty: "const slint::cbindgen_private::types::StaticTextures".into(),
name: format!("slint_embedded_resource_{}", er.id), name: format!("slint_embedded_resource_{}", er.id),
array_size: None, array_size: None,
init: Some(init), init: Some(init),
..Default::default()
})) }))
} }
#[cfg(feature = "software-renderer")] #[cfg(feature = "software-renderer")]
@ -649,19 +716,20 @@ pub fn generate(
let family_name_var = format!("slint_embedded_resource_{}_family_name", er.id); let family_name_var = format!("slint_embedded_resource_{}_family_name", er.id);
let family_name_size = family_name.len(); let family_name_size = family_name.len();
file.declarations.push(Declaration::Var(Var { file.declarations.push(Declaration::Var(Var {
ty: "inline const uint8_t".into(), ty: "const uint8_t".into(),
name: family_name_var.clone(), name: family_name_var.clone(),
array_size: Some(family_name_size), array_size: Some(family_name_size),
init: Some(format!( init: Some(format!(
"{{ {} }}", "{{ {} }}",
family_name.as_bytes().iter().map(ToString::to_string).join(", ") family_name.as_bytes().iter().map(ToString::to_string).join(", ")
)), )),
..Default::default()
})); }));
let charmap_var = format!("slint_embedded_resource_{}_charmap", er.id); let charmap_var = format!("slint_embedded_resource_{}_charmap", er.id);
let charmap_size = character_map.len(); let charmap_size = character_map.len();
file.declarations.push(Declaration::Var(Var { file.declarations.push(Declaration::Var(Var {
ty: "inline const slint::cbindgen_private::CharacterMapEntry".into(), ty: "const slint::cbindgen_private::CharacterMapEntry".into(),
name: charmap_var.clone(), name: charmap_var.clone(),
array_size: Some(charmap_size), array_size: Some(charmap_size),
init: Some(format!( init: Some(format!(
@ -674,12 +742,13 @@ pub fn generate(
)) ))
.join(", ") .join(", ")
)), )),
..Default::default()
})); }));
for (glyphset_index, glyphset) in glyphs.iter().enumerate() { for (glyphset_index, glyphset) in glyphs.iter().enumerate() {
for (glyph_index, glyph) in glyphset.glyph_data.iter().enumerate() { for (glyph_index, glyph) in glyphset.glyph_data.iter().enumerate() {
file.declarations.push(Declaration::Var(Var { file.declarations.push(Declaration::Var(Var {
ty: "inline const uint8_t".into(), ty: "const uint8_t".into(),
name: format!( name: format!(
"slint_embedded_resource_{}_gs_{}_gd_{}", "slint_embedded_resource_{}_gs_{}_gd_{}",
er.id, glyphset_index, glyph_index er.id, glyphset_index, glyph_index
@ -689,11 +758,12 @@ pub fn generate(
"{{ {} }}", "{{ {} }}",
glyph.data.iter().map(ToString::to_string).join(", ") glyph.data.iter().map(ToString::to_string).join(", ")
)), )),
..Default::default()
})); }));
} }
file.declarations.push(Declaration::Var(Var{ file.declarations.push(Declaration::Var(Var{
ty: "inline const slint::cbindgen_private::BitmapGlyph".into(), ty: "const slint::cbindgen_private::BitmapGlyph".into(),
name: format!("slint_embedded_resource_{}_glyphset_{}", er.id, glyphset_index), name: format!("slint_embedded_resource_{}_glyphset_{}", er.id, glyphset_index),
array_size: Some(glyphset.glyph_data.len()), array_size: Some(glyphset.glyph_data.len()),
init: Some(format!("{{ {} }}", glyphset.glyph_data.iter().enumerate().map(|(glyph_index, glyph)| { init: Some(format!("{{ {} }}", glyphset.glyph_data.iter().enumerate().map(|(glyph_index, glyph)| {
@ -703,13 +773,14 @@ pub fn generate(
glyph.data.len() glyph.data.len()
) )
}).join(", \n"))), }).join(", \n"))),
..Default::default()
})); }));
} }
let glyphsets_var = format!("slint_embedded_resource_{}_glyphsets", er.id); let glyphsets_var = format!("slint_embedded_resource_{}_glyphsets", er.id);
let glyphsets_size = glyphs.len(); let glyphsets_size = glyphs.len();
file.declarations.push(Declaration::Var(Var { file.declarations.push(Declaration::Var(Var {
ty: "inline const slint::cbindgen_private::BitmapGlyphs".into(), ty: "const slint::cbindgen_private::BitmapGlyphs".into(),
name: glyphsets_var.clone(), name: glyphsets_var.clone(),
array_size: Some(glyphsets_size), array_size: Some(glyphsets_size),
init: Some(format!( init: Some(format!(
@ -726,6 +797,7 @@ pub fn generate(
)) ))
.join(", \n") .join(", \n")
)), )),
..Default::default()
})); }));
let init = format!( let init = format!(
@ -742,10 +814,11 @@ pub fn generate(
); );
file.declarations.push(Declaration::Var(Var { file.declarations.push(Declaration::Var(Var {
ty: "inline const slint::cbindgen_private::BitmapFont".into(), ty: "const slint::cbindgen_private::BitmapFont".into(),
name: format!("slint_embedded_resource_{}", er.id), name: format!("slint_embedded_resource_{}", er.id),
array_size: None, array_size: None,
init: Some(init), init: Some(init),
..Default::default()
})) }))
} }
} }
@ -896,7 +969,14 @@ pub fn generate(
file.includes.push("<cmath>".into()); file.includes.push("<cmath>".into());
} }
file let cpp_files = file.split_off_cpp_files(config.header_include, config.cpp_files.len());
for (cpp_file_name, cpp_file) in config.cpp_files.iter().zip(cpp_files) {
use std::io::Write;
write!(&mut BufWriter::new(std::fs::File::create(&cpp_file_name)?), "{}", cpp_file)?;
}
Ok(file)
} }
fn generate_struct( fn generate_struct(
@ -1043,7 +1123,7 @@ fn generate_public_component(
Access::Public, Access::Public,
Declaration::Function(Function { Declaration::Function(Function {
name: "show".into(), name: "show".into(),
signature: "()".into(), signature: "() -> void".into(),
statements: Some(vec!["window().show();".into()]), statements: Some(vec!["window().show();".into()]),
..Default::default() ..Default::default()
}), }),
@ -1053,7 +1133,7 @@ fn generate_public_component(
Access::Public, Access::Public,
Declaration::Function(Function { Declaration::Function(Function {
name: "hide".into(), name: "hide".into(),
signature: "()".into(), signature: "() -> void".into(),
statements: Some(vec!["window().hide();".into()]), statements: Some(vec!["window().hide();".into()]),
..Default::default() ..Default::default()
}), }),
@ -1073,7 +1153,7 @@ fn generate_public_component(
Access::Public, Access::Public,
Declaration::Function(Function { Declaration::Function(Function {
name: "run".into(), name: "run".into(),
signature: "()".into(), signature: "() -> void".into(),
statements: Some(vec![ statements: Some(vec![
"show();".into(), "show();".into(),
"slint::run_event_loop();".into(), "slint::run_event_loop();".into(),
@ -1493,7 +1573,7 @@ fn generate_item_tree(
)); ));
file.definitions.push(Declaration::Var(Var { file.definitions.push(Declaration::Var(Var {
ty: "inline const slint::private_api::ItemTreeVTable".to_owned(), ty: "const slint::private_api::ItemTreeVTable".to_owned(),
name: format!("{}::static_vtable", item_tree_class_name), name: format!("{}::static_vtable", item_tree_class_name),
init: Some(format!( init: Some(format!(
"{{ visit_children, get_item_ref, get_subtree_range, get_subtree, \ "{{ visit_children, get_item_ref, get_subtree_range, get_subtree, \
@ -2021,7 +2101,8 @@ fn generate_sub_component(
} }
else_ = "} else "; else_ = "} else ";
} }
let ret = if signature.contains("->") { "{}" } else { "" }; let ret =
if signature.contains("->") && !signature.contains("-> void") { "{}" } else { "" };
code.push(format!("{else_}return {ret};")); code.push(format!("{else_}return {ret};"));
target_struct.members.push(( target_struct.members.push((
field_access, field_access,
@ -2108,7 +2189,7 @@ fn generate_sub_component(
dispatch_item_function( dispatch_item_function(
"accessibility_action", "accessibility_action",
"(uint32_t index, const slint::cbindgen_private::AccessibilityAction &action) const", "(uint32_t index, const slint::cbindgen_private::AccessibilityAction &action) const -> void",
", action", ", action",
accessibility_action_cases, accessibility_action_cases,
); );
@ -2527,7 +2608,7 @@ fn generate_public_api_for_properties(
Access::Public, Access::Public,
Declaration::Function(Function { Declaration::Function(Function {
name: format!("set_{}", &prop_ident), name: format!("set_{}", &prop_ident),
signature: format!("(const {} &value) const", &cpp_property_type), signature: format!("(const {} &value) const -> void", &cpp_property_type),
statements: Some(prop_setter), statements: Some(prop_setter),
..Default::default() ..Default::default()
}), }),

View file

@ -20,8 +20,10 @@ pub fn test(testcase: &test_driver_lib::TestCase) -> Result<(), Box<dyn Error>>
let mut diag = BuildDiagnostics::default(); let mut diag = BuildDiagnostics::default();
let syntax_node = parser::parse(source.clone(), Some(&testcase.absolute_path), None, &mut diag); let syntax_node = parser::parse(source.clone(), Some(&testcase.absolute_path), None, &mut diag);
let output_format = let output_format = generator::OutputFormat::Cpp(generator::cpp::Config {
generator::OutputFormat::Cpp(generator::cpp::Config { namespace: cpp_namespace }); namespace: cpp_namespace,
..Default::default()
});
let mut compiler_config = CompilerConfiguration::new(output_format.clone()); let mut compiler_config = CompilerConfiguration::new(output_format.clone());
compiler_config.include_paths = include_paths; compiler_config.include_paths = include_paths;

View file

@ -70,6 +70,10 @@ struct Cli {
/// C++ namespace /// C++ namespace
#[arg(long = "cpp-namespace", name = "C++ namespace")] #[arg(long = "cpp-namespace", name = "C++ namespace")]
cpp_namespace: Option<String>, cpp_namespace: Option<String>,
/// C++ files to generate (0 for header-only output)
#[arg(long = "cpp-file", name = "C++ file to generate", number_of_values = 1, action)]
cpp_files: Vec<std::path::PathBuf>,
} }
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
@ -89,8 +93,28 @@ fn main() -> std::io::Result<()> {
if !matches!(format, generator::OutputFormat::Cpp(..)) { if !matches!(format, generator::OutputFormat::Cpp(..)) {
eprintln!("C++ namespace option was set. Output format will be C++."); eprintln!("C++ namespace option was set. Output format will be C++.");
} }
format = format = generator::OutputFormat::Cpp(generator::cpp::Config {
generator::OutputFormat::Cpp(generator::cpp::Config { namespace: args.cpp_namespace }); namespace: args.cpp_namespace,
..Default::default()
});
}
if !args.cpp_files.is_empty() {
match &mut format {
generator::OutputFormat::Cpp(ref mut config) => {
config.cpp_files = args.cpp_files;
if args.output == std::path::Path::new("-") {
eprintln!("--cpp-file can only be used together with -o");
std::process::exit(1);
}
config.header_include = args.output.to_string_lossy().to_string();
}
_ => {
eprintln!("C++ files option was set but the output format is not C++ - ignorning");
}
}
} }
let mut compiler_config = CompilerConfiguration::new(format.clone()); let mut compiler_config = CompilerConfiguration::new(format.clone());