diff options
| author | ruki <[email protected]> | 2024-07-25 12:47:50 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-07-25 12:47:50 +0800 |
| commit | deef593df0fc604b0da9fe735edf30e31c82af8c (patch) | |
| tree | 4be14639a997cdae2ce2da0fad7b36159ec119db /xmake/rules/c++/modules/modules_support | |
| parent | 2eac22e42e4ebeebbcdd5e241fea4fcaf7a92e59 (diff) | |
| parent | 626b80e46c371a2723f204e2412339e73d6cbece (diff) | |
Merge pull request #5376 from Arthapz/fix-module-objectfiles-handling
Improve module objectfiles handling and moduleonly package
Diffstat (limited to 'xmake/rules/c++/modules/modules_support')
6 files changed, 125 insertions, 166 deletions
diff --git a/xmake/rules/c++/modules/modules_support/clang/builder.lua b/xmake/rules/c++/modules/modules_support/clang/builder.lua index b10a47e06..91534a11e 100644 --- a/xmake/rules/c++/modules/modules_support/clang/builder.lua +++ b/xmake/rules/c++/modules/modules_support/clang/builder.lua @@ -207,11 +207,7 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) job = batchjobs:newjob(name or opt.cppfile, function(index, total, jobopt) local mapped_bmi if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then - if not target:is_binary() then - return - else - mapped_bmi = get_from_target_mapper(target, name).bmi - end + mapped_bmi = get_from_target_mapper(target, name).bmi end local build, dependinfo @@ -248,24 +244,16 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) local fileconfig = target:fileconfig(opt.cppfile) local public = fileconfig and fileconfig.public local external = fileconfig and fileconfig.external - local private_dep = fileconfig and fileconfig.private_dep + local from_moduleonly = external and external.moduleonly local bmifile = mapped_bmi or bmifile - if target:is_binary() then - if mapped_bmi then - progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.objectfile.$(mode) %s", target:name(), name or opt.cppfile) - _compile_objectfile_step(target, bmifile, opt.cppfile, opt.objectfile) - else - progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, {std = (name == "std" or name == "std.compat")}) - end - else - if (not public and not external) or (external and private_dep) then - progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, {std = (name == "std" or name == "std.compat")}) - else + if external and not from_moduleonly then + if not mapped_bmi then progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile) _compile_bmi_step(target, bmifile, opt.cppfile, {std = (name == "std" or name == "std.compat")}) end + else + progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) + _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, {std = (name == "std" or name == "std.compat")}) end else os.tryrm(opt.objectfile) -- force rebuild for .cpp files @@ -283,11 +271,7 @@ function make_module_buildcmds(target, batchcmds, opt) local mapped_bmi if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then - if not target:is_binary() then - return - else - mapped_bmi = get_from_target_mapper(target, name).bmi - end + mapped_bmi = get_from_target_mapper(target, name).bmi end -- append requires flags @@ -302,24 +286,15 @@ function make_module_buildcmds(target, batchcmds, opt) local fileconfig = target:fileconfig(opt.cppfile) local public = fileconfig and fileconfig.public local external = fileconfig and fileconfig.external - local private_dep = fileconfig and fileconfig.private_dep local bmifile = mapped_bmi or bmifile - if target:is_binary() then - if mapped_bmi then - batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.objectfile.$(mode) %s", target:name(), name or opt.cppfile) - _compile_objectfile_step(target, bmifile, opt.cppfile, opt.objectfile, {batchcmds = batchcmds}) - else - batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, {std = (name == "std" or name == "std.compat"), batchcmds = batchcmds}) - end - else - if (not public and not external) or (external and private_dep) then - batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, {std = (name == "std" or name == "std.compat"), batchcmds = batchcmds}) - else + if external and not from_moduleonly then + if not mapped_bmi then batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile) _compile_bmi_step(target, bmifile, opt.cppfile, {std = (name == "std" or name == "std.compat"), batchcmds = batchcmds}) end + else + batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) + _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, {std = (name == "std" or name == "std.compat"), batchcmds = batchcmds}) end else batchcmds:rm(opt.objectfile) -- force rebuild for .cpp files diff --git a/xmake/rules/c++/modules/modules_support/compiler_support.lua b/xmake/rules/c++/modules/modules_support/compiler_support.lua index a005dc80d..7c4e665d0 100644 --- a/xmake/rules/c++/modules/modules_support/compiler_support.lua +++ b/xmake/rules/c++/modules/modules_support/compiler_support.lua @@ -83,33 +83,6 @@ function patch_sourcebatch(target, sourcebatch) end end --- cull sourcebatch objectfiles -function cull_objectfiles(target, modules, sourcebatch) - - -- don't cull for executables - if target:is_binary() then - return - end - - sourcebatch.objectfiles = {} - for _, sourcefile in ipairs(sourcebatch.sourcefiles) do - local objectfile = target:objectfile(sourcefile) - local module = modules[objectfile] - local _, provide, _ = get_provided_module(module) - if provide then - local fileconfig = target:fileconfig(sourcefile) - local public = fileconfig and fileconfig.public - local external = fileconfig and fileconfig.external - local private_dep = fileconfig and fileconfig.private_dep - if (not public and not external) or (external and private_dep) then - table.insert(sourcebatch.objectfiles, objectfile) - end - else - table.insert(sourcebatch.objectfiles, objectfile) - end - end -end - -- get bmi extension function get_bmi_extension(target) return _compiler_support(target).get_bmi_extension() diff --git a/xmake/rules/c++/modules/modules_support/dependency_scanner.lua b/xmake/rules/c++/modules/modules_support/dependency_scanner.lua index 66b00f421..c8da6793a 100644 --- a/xmake/rules/c++/modules/modules_support/dependency_scanner.lua +++ b/xmake/rules/c++/modules/modules_support/dependency_scanner.lua @@ -175,15 +175,25 @@ end -- generate edges for DAG function _get_edges(nodes, modules) local edges = {} - for _, node in ipairs(nodes) do + local module_names = {} + local name_filemap = {} + local named_module_names = hashset.new() + for _, node in ipairs(table.unique(nodes)) do local module = modules[node] + local module_name, _, cppfile = compiler_support.get_provided_module(module) + if module_name then + if named_module_names:has(module_name) then + raise("duplicate module name detected \"" .. module_name .. "\"\n -> " .. cppfile .. "\n -> " .. name_filemap[module_name]) + end + named_module_names:insert(module_name) + name_filemap[module_name] = cppfile + end if module.requires then for required_name, _ in table.orderpairs(module.requires) do for _, required_node in ipairs(nodes) do local name, _, _ = compiler_support.get_provided_module(modules[required_node]) if name and name == required_name then table.insert(edges, {required_node, node}) - break end end end @@ -200,7 +210,8 @@ function _get_package_modules(target, package, opt) for _, metafile in ipairs(metafiles) do package_modules = package_modules or {} local modulefile, name, metadata = _parse_meta_info(target, metafile) - package_modules[name] = {file = path.join(modulesdir, modulefile), metadata = metadata} + local moduleonly = not package:libraryfiles() + package_modules[name] = {file = path.join(modulesdir, modulefile), metadata = metadata, external = {moduleonly = moduleonly}} end return package_modules @@ -396,8 +407,9 @@ function get_all_packages_modules(target, opt) end -- topological sort -function sort_modules_by_dependencies(target, objectfiles, modules) - local result = {} +function sort_modules_by_dependencies(target, objectfiles, modules, opt) + local build_objectfiles = {} + local link_objectfiles = {} local edges = _get_edges(objectfiles, modules) local dag = graph.new(true) for _, e in ipairs(edges) do @@ -414,31 +426,74 @@ function sort_modules_by_dependencies(target, objectfiles, modules) table.insert(names, name or cppfile) raise("circular modules dependency detected!\n%s", table.concat(names, "\n -> import ")) end - local objectfiles_sorted = dag:topological_sort() - for _, objectfile in ipairs(objectfiles_sorted) do - table.insert(result, objectfile) - end + local objectfiles_sorted = table.reverse(dag:topological_sort()) local objectfiles_sorted_set = hashset.from(objectfiles_sorted) for _, objectfile in ipairs(objectfiles) do if not objectfiles_sorted_set:has(objectfile) then - if target:policy("build.c++.modules.culling") then - -- cull unreferenced non-public named module but add non-module files and implementation modules - local _, provide, cppfile = compiler_support.get_provided_module(modules[objectfile]) - local fileconfig = target:fileconfig(cppfile) + table.insert(objectfiles_sorted, objectfile) + objectfiles_sorted_set:insert(objectfile) + end + end + local culleds + for _, objectfile in ipairs(objectfiles_sorted) do + local name, provide, cppfile = compiler_support.get_provided_module(modules[objectfile]) + local fileconfig = target:fileconfig(cppfile) + local public + local external + local can_cull = true + if fileconfig then + public = fileconfig.public + external = fileconfig.external + can_cull = fileconfig.cull == nil and true or fileconfig.cull + end + can_cull = can_cull and target:policy("build.c++.modules.culling") + local insert = true + if provide then + insert = public or (not external or external.moduleonly) + if insert and not public and can_cull then + insert = false + local edges = dag:adjacent_edges(objectfile) local public = fileconfig and fileconfig.public - local dont_cull = fileconfig and fileconfig.cull ~= nil and not fileconfig.cull - if not provide or public or dont_cull then - table.insert(result, objectfile) - else - wprint("%s has been culled because it's not consumed by its target nor flagged as a public module (add_files(\"xxx.cppm\", {public = true}))", cppfile) + if edges then + for _, edge in ipairs(edges) do + if edge:to() ~= objectfile and objectfiles_sorted_set:has(edge:to()) then + insert = true + break + end + end end - else - table.insert(result, objectfile) end end + if insert then + table.insert(build_objectfiles, objectfile) + table.insert(link_objectfiles, objectfile) + elseif external and not external.from_moduleonly then + table.insert(build_objectfiles, objectfile) + else + objectfiles_sorted_set:remove(objectfile) + if name ~= "std" and name ~= "std.compat" then + culleds = culleds or {} + culleds[target:name()] = culleds[target:name()] or {} + table.insert(culleds[target:name()], format("%s -> %s", name, cppfile)) + end + end + end + + if culleds then + if option.get("verbose") then + local culled_strs = {} + for target_name, m in pairs(culleds) do + table.insert(culled_strs, format("%s:\n %s", target_name, table.concat(m, "\n "))) + end + wprint("some modules have got culled, because it is not consumed by its target nor flagged as a public module with add_files(\"xxx.mpp\", {public = true})\n %s", + table.concat(culled_strs, "\n ")) + else + wprint("some modules have got culled, use verbose (-v) mode to more informations") + end end - return result + + return build_objectfiles, link_objectfiles end -- get source modulefile for external target deps @@ -446,7 +501,6 @@ function get_targetdeps_modules(target) local sourcefiles for _, dep in ipairs(target:orderdeps()) do local sourcebatch = dep:sourcebatches()["c++.build.modules.builder"] - local private_dep = target:extraconf("deps", dep:name(), "private") or not target:extraconf("deps", dep:name(), "public") if sourcebatch and sourcebatch.sourcefiles then for _, sourcefile in ipairs(sourcebatch.sourcefiles) do local fileconfig = dep:fileconfig(sourcefile) @@ -454,7 +508,7 @@ function get_targetdeps_modules(target) if public then sourcefiles = sourcefiles or {} table.insert(sourcefiles, sourcefile) - target:fileconfig_add(sourcefile, {external = true, private_dep = private_dep}) + target:fileconfig_add(sourcefile, {external = {moduleonly = dep:is_moduleonly()}}) end end end diff --git a/xmake/rules/c++/modules/modules_support/gcc/builder.lua b/xmake/rules/c++/modules/modules_support/gcc/builder.lua index d4f5a01f1..a0a43db5a 100644 --- a/xmake/rules/c++/modules/modules_support/gcc/builder.lua +++ b/xmake/rules/c++/modules/modules_support/gcc/builder.lua @@ -187,11 +187,7 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) job = batchjobs:newjob(name or opt.cppfile, function(index, total, jobopt) local mapped_bmi if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then - if not target:is_binary() then - return - else - mapped_bmi = get_from_target_mapper(target, name).bmi - end + mapped_bmi = get_from_target_mapper(target, name).bmi end -- generate and append module mapper file @@ -215,33 +211,27 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) local fileconfig = target:fileconfig(opt.cppfile) local public = fileconfig and fileconfig.public local external = fileconfig and fileconfig.external - local private_dep = fileconfig and fileconfig.private_dep + local from_moduleonly = external and external.moduleonly local bmifile = mapped_bmi or bmifile local flags = {"-x", "c++"} local sourcefile - if target:is_binary() then - if mapped_bmi then - progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.objectfile.$(mode) %s", target:name(), name or opt.cppfile) - sourcefile = bmifile - else - progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - sourcefile = opt.cppfile - end - else - if (not public and not external) or (external and private_dep) then - progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - sourcefile = opt.cppfile - else + if external and not from_moduleonly then + if not mapped_bmi then progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile) local module_onlyflag = compiler_support.get_moduleonlyflag(target) table.insert(flags, module_onlyflag) sourcefile = opt.cppfile end + else + progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) + sourcefile = opt.cppfile end if option.get("diagnosis") then print("mapper file --------\n%s--------", io.readfile(module_mapper)) end - _compile(target, flags, sourcefile, opt.objectfile) + if sourcefile then + _compile(target, flags, sourcefile, opt.objectfile) + end os.tryrm(module_mapper) else os.tryrm(opt.objectfile) -- force rebuild for .cpp files @@ -260,11 +250,7 @@ function make_module_buildcmds(target, batchcmds, opt) local mapped_bmi if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then - if not target:is_binary() then - return - else - mapped_bmi = get_from_target_mapper(target, name).bmi - end + mapped_bmi = get_from_target_mapper(target, name).bmi end -- generate and append module mapper file @@ -280,33 +266,27 @@ function make_module_buildcmds(target, batchcmds, opt) local fileconfig = target:fileconfig(opt.cppfile) local public = fileconfig and fileconfig.public local external = fileconfig and fileconfig.external - local private_dep = fileconfig and fileconfig.private_dep + local from_moduleonly = external and external.moduleonly local bmifile = mapped_bmi or bmifile local flags = {"-x", "c++"} local sourcefile - if target:is_binary() then - if mapped_bmi then - batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.objectfile.$(mode) %s", target:name(), name or opt.cppfile) - sourcefile = bmifile - else - batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - sourcefile = opt.cppfile - end - else - if (not public and not external) or (external and private_dep) then - batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - sourcefile = opt.cppfile - else + if external and not from_moduleonly then + if not mapped_bmi then batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile) local module_onlyflag = compiler_support.get_moduleonlyflag(target) table.insert(flags, module_onlyflag) sourcefile = opt.cppfile end + else + batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) + sourcefile = opt.cppfile end if option.get("diagnosis") then batchcmds:print("mapper file: %s", io.readfile(module_mapper)) end - _batchcmds_compile(batchcmds, target, flags, sourcefile, opt.objectfile) + if sourcefile then + _batchcmds_compile(batchcmds, target, flags, sourcefile, opt.objectfile) + end batchcmds:rm(module_mapper) else batchcmds:rm(opt.objectfile) -- force rebuild for .cpp files diff --git a/xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua b/xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua index 2253c9866..25e047f8a 100644 --- a/xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua +++ b/xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua @@ -77,6 +77,7 @@ function strip_flags(target, flags) "-w", "-cxx-isystem", "-Q", + "-fmodule-mapper", } if not target:policy("build.c++.modules.tryreuse.discriminate_on_defines") then table.join2(strippable_flags, {"-D", "-U"}) diff --git a/xmake/rules/c++/modules/modules_support/msvc/builder.lua b/xmake/rules/c++/modules/modules_support/msvc/builder.lua index ccdbea141..89d9b6b60 100644 --- a/xmake/rules/c++/modules/modules_support/msvc/builder.lua +++ b/xmake/rules/c++/modules/modules_support/msvc/builder.lua @@ -271,11 +271,7 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) local mapped_bmi if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then - if not target:is_binary() then - return - else - mapped_bmi = get_from_target_mapper(target, name).bmi - end + mapped_bmi = get_from_target_mapper(target, name).bmi end local build, dependinfo @@ -312,24 +308,16 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) local fileconfig = target:fileconfig(opt.cppfile) local public = fileconfig and fileconfig.public local external = fileconfig and fileconfig.external - local private_dep = fileconfig and fileconfig.private_dep + local from_moduleonly = external and external.moduleonly local bmifile = mapped_bmi or bmifile - if target:is_binary() then - if mapped_bmi then - progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.objectfile.$(mode) %s", target:name(), name or opt.cppfile) - _compile_objectfile_step(target, bmifile, opt.cppfile, opt.objectfile, provide) - else - progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, provide) - end - else - if (not public and not external) or (external and private_dep) then - progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, provide) - else + if external and not from_moduleonly then + if not mapped_bmi then progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile) _compile_bmi_step(target, bmifile, opt.cppfile, opt.objectfile, provide) end + else + progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) + _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, provide) end else os.tryrm(opt.objectfile) -- force rebuild for .cpp files @@ -347,11 +335,7 @@ function make_module_buildcmds(target, batchcmds, opt) local mapped_bmi if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then - if not target:is_binary() then - return - else - mapped_bmi = get_from_target_mapper(target, name).bmi - end + mapped_bmi = get_from_target_mapper(target, name).bmi end -- append requires flags @@ -366,24 +350,16 @@ function make_module_buildcmds(target, batchcmds, opt) local fileconfig = target:fileconfig(opt.cppfile) local public = fileconfig and fileconfig.public local external = fileconfig and fileconfig.external - local private_dep = fileconfig and fileconfig.private_dep + local from_moduleonly = external and external.moduleonly local bmifile = mapped_bmi or bmifile - if target:is_binary() then - if mapped_bmi then - batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.objectfile.$(mode) %s", target:name(), name or opt.cppfile) - _compile_objectfile_step(target, bmifile, opt.cppfile, opt.objectfile, provide, {batchcmds = batchcmds}) - else - batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, provide, {batchcmds = batchcmds}) - end - else - if (not public and not external) or (external and private_dep) then - batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) - _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, provide, {batchcmds = batchcmds}) - else + if external and not from_moduleonly then + if not mapped_bmi then batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile) _compile_bmi_step(target, bmifile, opt.cppfile, provide, {batchcmds = batchcmds}) end + else + batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile) + _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, provide, {batchcmds = batchcmds}) end else batchcmds:rm(opt.objectfile) -- force rebuild for .cpp files |
