Build systems address the question: "To produce this artifact, which inputs must be prepared first, and what changes require redoing which steps?" Writing a command that compiles is just the starting point; whether incremental builds, parallelism, and dependency propagation are correct depends on whether the dependency graph is complete.
Make executes tasks based on rules and file states. CMake and Meson typically configure first, generate backend build descriptions, and then hand them over to executors like Ninja or Make. You cannot directly compare the configuration time of CMake with the compilation time of Ninja to conclude that one language is inherently slower to build.
The Same Minimal Project
The following three approaches build the same set of files, with source code located in the project root:
Modifying lib.c should rebuild the library and relink; modifying the common header lib.h should cause both consumers to recompile. Building with no changes should result in no unnecessary compilation actions. Missing this header dependency can lead to mixing old declarations with the new library, a problem that "full build success" alone cannot detect.
GNU Make: Rules, Variables, and Automatic Dependencies
Save as Makefile. The first character of the recipe lines below is an actual Tab, not a regular space:
Here, $@ is the target, $< is the first prerequisite, and $^ is the list of unique prerequisites. Placing library arguments after the objects that reference them is the correct order under traditional static library extraction rules.
CPPFLAGS holds preprocessor arguments, CFLAGS holds C compiler arguments, LDFLAGS holds linker options, and LDLIBS holds library dependencies like -lm. Categorizing them allows callers to override one class without affecting others.
Compile time also generates .d files for each object. -MMD usually omits system header dependencies, -MP generates auxiliary empty rules for headers, and -include allows the first build when .d files do not yet exist. Make can only know about indirect include relationships after reading the generated files. GNU Make Automatic Prerequisites
make -j4./progmake
Make primarily relies on timestamps and dependencies to determine if updates are needed, and by default does not record "command line arguments changed." In this example, treating the Makefile itself as an object dependency means editing the file triggers recompilation, but changing CFLAGS via command line will not automatically invalidate old objects; real projects can use configuration signatures, separate build directories, or clean up when switching configurations.
Generating header files must also explicitly declare the generation action; without .d files before the first build, relying solely on automatic scanning cannot guarantee the generator runs first. Output directories are generally suitable as order-only prerequisites to avoid triggering unnecessary recompilations due to directory timestamp changes.
CMake: Targets Carry Usage Requirements
Save as CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(demo VERSION 1.0 LANGUAGES C)
add_library(demo STATIC lib.c)
target_include_directories(demo PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_compile_features(demo PUBLIC c_std_11)
add_executable(prog main.c)
target_link_libraries(prog PRIVATE demo)
PUBLIC means that both building demo itself and targets using demo need this property; PRIVATE serves only the target itself, and INTERFACE is passed only to users. If a header has a public dependency on a type, compile definition, or language feature, you must consider whether the corresponding usage requirement should propagate. CMake Build System
"Implementation dependencies not public" for static libraries does not mean the final link never needs them; the build system handles link dependency propagation according to target types. Use target relationships; do not copy include paths, library names, and global flags everywhere.
CMAKE_BUILD_TYPE applies to single-config generators in examples. Multi-config generators usually select via --config Release at build time; do not mix the two models. The compile database records actual compilation commands, suitable for tools like clangd; see LSP and Language Servers.
Meson: Explicitly Declare Targets and Dependencies
Use a dependency object to pass both link libraries and include requirements together, avoiding consumers missing one. Optimization and debugging strategies are usually expressed via buildtype or options; there is no need to hardcode -O2 into the c_args of every target, especially when considering different compilers. Meson Targets, Meson Dependencies
A directory that has already been setup can be reconfigured; independent build directories help avoid cache mixing when changing critical environments like the compiler or cross-configuration. Whether configuration automatically downloads certain fallback dependencies is determined by the project and options; do not universally understand dependency() as a package manager install command.
Adding Generated Header Files to Verify the Complete Build Graph
Write factor.txt as the integer 2, and add the following generate.py. It only accepts 1–100 to avoid injecting arbitrary input directly into C source code; output is placed at the location specified by the command.
frompathlibimportPathimportsyssource, output=map(Path,sys.argv[1:])factor=int(source.read_text().strip())ifnot1<=factor<=100:raiseSystemExit("factor must be in 1..100")output.write_text(f"#define DEMO_FACTOR {factor}\n")
Replace lib.c and main.c with the following content respectively, keeping lib.h with the previous declaration. twice retains the original function name, but the actual multiplier is now controlled by configuration; the example only calls with 21, so the range will not cause int overflow.
/* lib.c */#include"lib.h"#include"generated.h"inttwice(intx){return x * DEMO_FACTOR;}
Both objects must depend on generated.h; you cannot just let the final prog depend on it, otherwise parallel builds might start compiling source code missing the header. Here, the generated header is a normal prerequisite: it should trigger recompilation of consumers when it changes. If mistakenly written as order-only, it only guarantees sequence, not the requirement to recompile due to content changes.
After the first successful compilation, .d files will further record actual include relationships, but the generation rules for the first build still require manual edge creation. When generating multiple outputs, ensure they belong to the same correct rule to avoid multiple tasks writing to the same file simultaneously.
CMake Uses a Unique Generation Target to Connect Multiple Consumers
Add the following snippet to the existing CMakeLists.txt, placed after demo and prog are defined:
Custom commands have file outputs; the common generation target ensures both consumers compile after generation is complete; fine-grained recompilation after header content changes is handled by compile dependency scanning. VERBATIM helps correctly pass path arguments, avoiding manual shell quote concatenation. If the generator also produces necessary side effects, declare them using BYPRODUCTS in applicable versions; do not hide inputs needed by Ninja inside the command. CMake Custom Output
Meson Places the Generation Target in the Consumer's Source List
Here, include_directories('.') includes the corresponding source and build directories; header in the consumer's source list expresses generation order. generate.py participates in the command as a file object, factor.txt is an explicit input, and changes to both enter the build judgment. You cannot just write an include path pointing to a future generation directory and expect the build system to infer who the producer is. Meson Generating Sources
Checking Three Build Approaches with Four Changes
It is recommended to use separate source copies for the three experiments: Make generates generated.h in the source directory, while CMake/Meson generate in their respective build directories. If using the same source directory, C's quoted includes might find Make's leftover headers first, causing the other build to use the wrong generated result.
Change
Expected Action
Problem Discovered
Fresh directory, parallel build
Generate first, then compile two objects, then link
Missing first-time dependencies
Build again with no modifications
No generation or compilation actions
Unconditional execution leads to wasted work
Change factor.txt from 2 to 3
Regenerate, recompile consumers, relink
Expressing sequence only without expressing change
Delete generated.h
Automatically rebuild output and restore successful build
Output not registered or dependency cache hides issues
The generator in this example updates timestamps every time it actually executes, facilitating understanding of propagation. If adopting "do not rewrite if content is unchanged" to reduce subsequent compilations, Make must also handle the case where inputs are newer than outputs to avoid always re-running the generator; you cannot assume incremental behavior is complete just by modifying the Python write logic; you must design the relationship between stamp and real output according to project needs.
With One Edge Missing, Which Artifacts Quietly Become Stale?
Changes to the generated header content need to invalidate both main.o and lib.o. Removing the edge to main.o, even if linking is still triggered by another path, main.o might continue using old macro values, forming a mixed-version artifact. Fresh builds also need these edges to ensure generation precedes compilation; incremental correctness and first-time parallel correctness should be verified separately.
Preparing the visual
With One Edge Missing, Which Artifacts Quietly Become Stale?
Build graphs need to propagate from changed inputs to all consumers. Letting only the final program depend on the generated header cannot replace the compilation dependencies of object files.
{"id":"build-dependency-propagation","title":"With One Edge Missing, Which Artifacts Quietly Become Stale?","summary":"Build graphs need to propagate from changed inputs to all consumers. Letting only the final program depend on the generated header cannot replace the compilation dependencies of object files.","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"presets\" role=\"group\" data-i18n-label=\"input\"><button data-mode=\"factor\" data-i18n=\"factor\"></button><button data-mode=\"main\" data-i18n=\"main\"></button><button data-mode=\"lib\" data-i18n=\"lib\"></button></div><label class=\"check\"><input type=\"checkbox\" id=\"omit\"><span data-i18n=\"omit\"></span></label><svg id=\"dag\" class=\"diagram\" viewBox=\"0 0 360 245\" role=\"img\" data-i18n-label=\"heading\"></svg><div class=\"metrics\"><div><span data-i18n=\"required\"></span><strong id=\"required\"></strong></div><div><span data-i18n=\"scheduled\"></span><strong id=\"scheduled\"></strong></div><div><span data-i18n=\"stale\"></span><strong id=\"stale\"></strong></div></div><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 var(--viz-font-mono);white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px var(--viz-font-ui)}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 var(--viz-font-mono);white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:var(--viz-font-ui)}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.budget{display:flex;height:28px;margin:16px 0;background:var(--surface);border-radius:5px;overflow:hidden}.budget i{display:block;background:var(--accent);transition:width .2s}.budget i.gold{background:var(--second)}.intervals{margin:16px 0}.interval{position:relative;height:36px;background:var(--surface);margin:6px 0;border-radius:4px;overflow:hidden}.interval i{position:absolute;height:100%;background:var(--accent-soft);border-left:2px solid var(--accent)}.interval i.gold{background:var(--second-soft);border-color:var(--second)}.interval span{position:relative;z-index:1;font:12px/36px var(--viz-font-ui);padding-left:7px}.table .tr>*{min-height:4.8em}.formula{white-space:pre-line;min-height:7.2em}.actions:has(>button:only-child){grid-template-columns:1fr}.metrics strong{min-height:3.2em}.rangegrid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:3px;margin:14px 0}.rangegrid .cell{min-height:30px;padding:3px 1px;font-size:10px}.message{min-height:7.2em;white-space:pre-line;font:13px/1.8 var(--viz-font-ui);overflow-wrap:anywhere}\n/* Allow CJK hanging punctuation without overflowing a metric's border box. */\n.metrics>div{padding-right:4px}.metrics span{line-break:anywhere}\n\n.metrics strong{font-size:17px}.diagram text{font-size:10px}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).classList.add('table');$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}function band(id,parts,total){$('#'+id).replaceChildren(...parts.map((p,i)=>{const e=document.createElement('i');e.style.width=(100*p.value/total)+'%';e.className=i%2?'gold':'on';e.title=p.name+': '+p.value;return e}));}function intervals(id,items,total){$('#'+id).replaceChildren(...items.map(p=>{const row=document.createElement('div');row.className='interval';const bar=document.createElement('i');bar.style.left=(100*p.start/total)+'%';bar.style.width=(100*(p.end-p.start)/total)+'%';bar.className=p.cls||'';const label=document.createElement('span');label.textContent=p.label;row.append(bar,label);return row;}));}let changed='factor';function draw(){pressed(changed);const omit=$('#omit').checked,truth=changed==='factor'?['main.o','lib.o']:[changed+'.o'],actual=truth.filter(n=>!(changed==='factor'&&omit&&n==='main.o')),miss=truth.filter(n=>!actual.includes(n));set('required',truth.join(', '));set('scheduled',actual.join(', '));set('stale',miss.join(', ')||'∅');$('#stale').dataset.items=JSON.stringify(miss);const nodes=[['factor.txt',180,20],['generated.h',180,80],['main.c',45,80],['lib.c',315,80],['main.o',90,150],['lib.o',270,150],['prog',180,220]],edges=[[0,1],[1,4],[1,5],[2,4],[3,5],[4,6],[5,6]],active=new Set(changed==='factor'?[0,1,...(omit?[5,6]:[4,5,6])]:changed==='main'?[2,4,6]:[3,5,6]);$('#dag').innerHTML=edges.map(([a,b])=>'<line x1=\"'+nodes[a][1]+'\" y1=\"'+(nodes[a][2]+12)+'\" x2=\"'+nodes[b][1]+'\" y2=\"'+(nodes[b][2]-12)+'\" stroke=\"'+(a===1&&b===4&&omit?'var(--second)':'var(--rule)')+'\" stroke-width=\"2\"'+(a===1&&b===4&&omit?' stroke-dasharray=\"5 4\"':'')+'/>').join('')+nodes.map(([name,x,y],i)=>'<rect x=\"'+(x-42)+'\" y=\"'+(y-12)+'\" width=\"84\" height=\"24\" rx=\"4\" fill=\"'+(active.has(i)?'var(--accent-soft)':'var(--surface)')+'\" stroke=\"'+(active.has(i)?'var(--accent)':'var(--rule)')+'\"/><text x=\"'+x+'\" y=\"'+(y+4)+'\" text-anchor=\"middle\">'+name+'</text>').join('');}document.querySelectorAll('[data-mode]').forEach(e=>e.onclick=()=>{changed=e.dataset.mode;draw()});$('#omit').onchange=draw;draw();","audio":false,"strings":{"factor":"factor.txt","heading":"With One Edge Missing, Which Artifacts Quietly Become Stale?","input":"Changed Input","intro":"Select a changed input and remove a generated header dependency, comparing actual needs with declared triggered rebuilds.","lib":"lib.c","main":"main.c","omit":"Missing generated.h → main.o","required":"Objects actually needing recompilation","reset":"Reset","scheduled":"Objects triggered by declared graph","scope":"Incremental invalidation analysis of a built project, not simulating timestamp precision, content hashes, or actual parallel execution. Dashed lines indicate intentionally omitted real dependencies.","scopeLabel":"Model Scope and Conventions","stale":"Omitted objects"}}
pkg-config: Querying Build Metadata for Installed Libraries
.pc files tell users about header locations, libraries, and related dependencies; they do not install libraries, nor do they guarantee the runtime loader can find them. Paths vary by distribution, architecture, and install prefix; do not hardcode them to /usr/lib64/pkgconfig.
A sample demo.pc content is as follows, should be saved as a text file, not executed as a shell script:
prefix=/usr/locallibdir=${prefix}/libincludedir=${prefix}/include
Name: demo
Description: Small example library
Version: 1.0
Libs: -L${libdir} -ldemo
Cflags: -I${includedir}
Distinguish between public dependencies and private dependencies needed for static linking; fill in Requires, Requires.private, and Libs.private as appropriate. --static queries more complete dependency information and does not alone force the linker to select all static libraries. pkg-config Author Guide
In CMake, prefer consuming imported targets to avoid copying ${ZLIB_LIBRARIES} while missing directories or link options:
Adding this to the previous CMakeLists.txt attaches dependencies to prog. If an applicable find_package(ZLIB) imported target already exists, you can use it directly without forcing it through pkg-config. FindPkgConfig
Cross-Compilation and Reproducible Builds
Code generators run during the build belong to the build machine; the final program belongs to the target machine. Cross-compilation requires specifying the compiler, sysroot, tools, and target dependency search paths separately; do not mistakenly use host machine .pc results and expect the linker to automatically correct the architecture.
CMake toolchain files and Meson cross files are used to describe these environments. More complete reproducibility also involves dependency versions, generators, environment variables, path embedding, and time information; using a specific build system does not automatically guarantee this.
How to Compare and Verify
Focus Area
Behavior to Verify
Correctness
Clean build, header file changes, generated file dependencies are all correct
Incremental Efficiency
No recompilation with no changes, local changes only update necessary targets
Parallelism
Multi-task builds do not exhibit sporadic missing files or race conditions
Configuration Switching
Debug, Release, different compilers do not mix old artifacts
Integration
Compile database, tests, installation, and package metadata meet project needs
Build speed mainly depends on real compilation work, dependency graph granularity, caching, and executors. Make also has a dependency graph, and CMake can generate Ninja; you cannot replace measurement with "imperative is slow, declarative is fast."