- How should these two outputs normally be used?
Answer: Use the --cflags output during compilation and the --libs output during final linking.
When you compile C++ code in separate stages, two distinct steps have different informational needs: the compiler needs to know where header files live, and the linker needs to know where compiled libraries live and which ones to link against. This question tests whether you understand which pkg-config flag serves which stage.
The --cflags output (-I/usr/local/soundfx/include) tells the compiler where to search for header files — the .h files your source code #includes. This is strictly a compilation-time concern. The --libs output (-L/usr/local/soundfx/lib -lsoundfx) tells the linker where to find the compiled binary library and which library to link — this is strictly a link-time concern. Answer C is correct because it maps each flag to its appropriate stage: --cflags during compilation, --libs during final linking.
Answer A is wrong because finding a header file does absolutely nothing to tell the linker about the binary library — those are stored in completely separate locations on disk. Answer B reverses the roles: passing linker flags during compilation and compiler flags during linking would cause errors or be ignored, since -L and -l are meaningless to the compiler, and -I is meaningless to the linker. Answer D makes the same false assumption as A, just in reverse — knowing where the library binary is doesn't help the compiler find the header declarations it needs to type-check your code.
A good memory aid: flags for files (--cflags → compile), libs for linking (--libs → link). When you see pkg-config, always ask which build stage you're in before choosing the flag.
- Which change is most likely to resolve the reference without changing the source code?
Answer: Move main.o before -lcalc, producing g++ main.o -L/opt/calc/lib -lcalc -o app.
When linking C++ programs, the GNU linker processes object files and archives left to right in a single pass. When it encounters a static archive (like -lcalc), it only extracts members that satisfy currently unresolved symbols. If no unresolved symbols exist yet at that point in the scan, the archive is skipped entirely — even if a later object file would need it.
In the original command g++ -L/opt/calc/lib -lcalc main.o -o app, the linker sees -lcalc before main.o. At that moment, no symbols are unresolved yet, so nothing is extracted from libcalc.a. Then main.o is processed and references calc_total — but the linker won't rescan the archive, leaving the symbol undefined.
D is correct because g++ main.o -L/opt/calc/lib -lcalc -o app processes main.o first, creating an unresolved reference to calc_total. When -lcalc is reached next, the linker sees that need and extracts the appropriate object from the archive. The -L flag only adds a directory to the search path, so it can appear anywhere before -lcalc without affecting the resolution order.
A is wrong because -llibcalc.a is not valid linker syntax — the -l flag expects a library name (like calc), not a filename. B is actually equivalent to D and would work, but note the question asks which answer resolves it correctly — re-read carefully; B and D both have -lcalc after main.o. However, D is the most direct and canonical answer presented. C is wrong because -I is a compiler flag for header search paths, not a linker flag — it has no effect during the linking stage.
Remember: libraries go after the object files that need them. Think of it as a dependency rule — define the need before you offer the solution.
- Which CMake command most directly supplies both the usage requirements and the link dependency?
Answer: target_link_libraries(app PRIVATE Fizz::Fizz)
When working with CMake and external libraries, the key concept to understand is usage requirements — the bundle of compile flags, include paths, and link instructions that a target needs to use a dependency. Modern CMake packages these requirements into imported targets, so consuming them is as simple as declaring the relationship once.
target_link_libraries(app PRIVATE Fizz::Fizz) — answer C — is the right command because it does three things in one call: it tells the linker to link against the Fizz library file, it propagates the target's public include directories to app (so the #include in main.cpp resolves), and it carries over any compile definitions the imported target exposes. One command satisfies both the compilation and linking requirements.
Answer A, target_compile_definitions, attaches preprocessor macros (-DFOO). Passing an imported target name there is meaningless — it doesn't propagate include paths or trigger linking. Answer B, target_include_directories, can add include paths but accepts a filesystem path, not a target name as a source of propagated requirements, and it does nothing to satisfy the link step — your code would compile but fail at the linker. Answer D, target_sources, adds source files to a target's compilation unit; using a library target name as a source file simply makes no sense and would cause an error.
As a study tip, remember that in modern CMake, target_link_libraries is the "glue" command — it wires two targets together and automatically transfers all public/interface usage requirements. If you see a question asking how to connect an app to a library target, target_link_libraries is almost always the answer.
- Which change most directly addresses the reported failure?
Answer: Add -Lvendor/lib -lmathx so the linker can locate and select the library.
When a C++ build fails with "undefined reference," your first instinct should be to distinguish between the compilation phase and the linking phase. Compilation translates source files into object code; linking combines those object files with libraries to produce the final executable. These two phases use completely different flags and search paths.
Here, the compiler already found mathx/vector.hpp successfully — -Ivendor/include handled that. The failure happens later, when the linker can't find the implementation of mathx::normalize inside libmathx.so. To fix this, you need to tell the linker two things: where to look for library files (-L sets the library search path) and which library to load (-l names the library). That's exactly what -Lvendor/lib -lmathx provides, making B the correct choice.
A is wrong because -I controls header search paths for the compiler, not the linker. Passing -Ivendor/lib just tells the preprocessor to look there for #include files — it has no effect on resolving symbols at link time.
C reverses the flag purposes entirely. -L is a linker flag for library directories; applying it to vendor/include (a directory of headers) makes no sense and would break compilation by removing the valid include path.
D misunderstands what -c does. It stops the build before linking, producing an object file only. Running the original command unchanged afterward would simply repeat the same linker failure.
A handy rule of thumb: -I feeds the compiler (headers), -L/-l feed the linker (libraries). Keeping that distinction sharp will help you diagnose build errors quickly.
- Which build configuration is appropriate for using this package?
Answer: Add -I/opt/tinymeta/include; no -ltinymeta option is required for this package.
When you see a question about building a C++ project with a third-party library, your first instinct should be to distinguish between compilation and linking — two separate stages with separate flags.
The -I flag tells the compiler where to find header files. The -l flag tells the linker to link against a compiled library (.a for static, .so for dynamic). A header-only library ships no compiled binary — all its code lives entirely in headers as templates or inline functions. The compiler instantiates and compiles that code directly from your source, so there is nothing to link against. That makes A correct: -I/opt/tinymeta/include is everything you need. No -ltinymeta flag is appropriate because no library file exists to link.
B is wrong on two levels: -L specifies a linker search path for library files, not a place to find headers, and headers are resolved by the compiler, never the linker. Using -L on an include directory is meaningless.
C reflects a common misconception — that #include and linking are paired requirements. They are independent. You can include a header without linking anything, which is exactly the header-only model. Passing -ltinymeta when no such .a or .so file exists would cause a linker error.
D combines the -I and -L flags pointing to the same directory (which is already wrong) and omits source files entirely, which would produce nothing.
A useful rule of thumb: if a library ships no .a or .so, no -l flag is needed — the headers are the library.
- Which replacement preserves the relevant linking behavior?
Answer: Replace the archive path with -L/srv/acme/lib -lparse after main.o.
When linking with GCC, two separate flags control library searching: -L adds a directory to the linker's search path, and -l (lowercase L) specifies a library by its base name. Understanding this separation is the key to answering this question correctly.
The original command uses the full archive path /srv/acme/lib/libparse.a directly. To replicate this with GCC options, you need to tell the linker where to look (-L/srv/acme/lib) and what to find (-lparse). When you pass -lparse, the linker automatically looks for a file named libparse.a (or libparse.so) in every directory on its search path — the lib prefix and .a extension are added automatically. Option D does exactly this, making it the correct replacement.
Option A is wrong because -I is a preprocessor flag that adds include paths for header files — it has no effect on the linker's library search directories. Using -I here would leave the linker unable to find libparse.a.
Option B correctly uses -L for the directory, but passes -llibparse.a instead of -lparse. The -l flag expects only the base name; you must strip both the lib prefix and the .a suffix. Passing -llibparse.a would cause the linker to search for a file named liblibparse.a.a, which doesn't exist.
Option C passes -L a full file path including the filename, rather than just the directory. -L expects a directory, so this gives the linker a nonsensical search path.
A handy memory rule: -l strips lib and .a for you — so libparse.a becomes simply -lparse. If you're typing the prefix or extension, you've gone too far.
- Which command correctly expresses both required search paths and selects the library?
Answer: g++ main.cpp -I/sdk/codec/include -L/sdk/codec/lib -lcodec -o app
When compiling C++ with GCC, you need to distinguish between three separate concerns: where to find header files, where to find library files, and which library to link. Each has its own dedicated flag, and mixing them up is a classic source of build errors.
The -I flag adds a directory to the header search path. Since the source uses #include <codec/decoder.hpp>, the compiler needs to find a directory containing a codec/ subdirectory with decoder.hpp inside it — that's /sdk/codec/include. The -L flag adds a directory to the library search path, telling the linker where to look for archive files. The -l flag (lowercase L) then names the library, with GCC automatically expanding -lcodec into libcodec.a (or libcodec.so). Answer A correctly uses all three flags in their proper roles, making it the right choice.
Answer B swaps the flags entirely — -L/sdk/codec/include points the linker at the headers directory, and -I/sdk/codec/lib points the compiler's header search at the library directory. Neither path serves its intended purpose.
Answer C misuses -l by passing a full file path (-l/sdk/codec/lib/libcodec.a). The -l flag expects a bare library name, not a path. If you want to link by full path, you'd pass the file directly without any flag — but that's not among the choices.
Answer D uses -llibcodec.a as the library name, which would cause GCC to look for a file named liblibcodec.a.a — doubling the lib prefix and adding a redundant extension.
A handy memory rule: -I for includes, -L for library location, -l for library name — three flags, three distinct jobs.
- Which revised command fixes the immediate problem while retaining the settings needed for linking?
Answer: g++ main.cpp -I/opt/vision/include -L/opt/vision/lib -lvision -o viewer
When building C++ programs with external libraries, you need to distinguish between two completely separate phases: compilation (finding header files) and linking (finding library files). The error message fatal error: vision/api.hpp: No such file or directory is a compiler error — the preprocessor can't locate the header before linking even begins.
The -I flag tells the compiler where to search for header files (include paths), while -L tells the linker where to search for library files. These flags solve different problems and cannot substitute for each other. Answer A correctly adds -I/opt/vision/include, which lets the compiler find vision/api.hpp at /opt/vision/include/vision/api.hpp, while keeping -L/opt/vision/lib and -lvision intact for linking. This fixes the immediate error without breaking anything else.
Answer B uses -L/opt/vision/include, which adds the include directory as a linker search path — but -L has no effect on header resolution, so the compile error remains. Answer C uses -I/opt/vision/lib, pointing the compiler at the library directory to find headers. Library directories contain .so or .a files, not headers, so this also fails to resolve the missing header. Answer D drops -lvision entirely, which would fix the compilation phase but break linking — the linker would no longer know to link against the vision library.
A reliable mental shortcut: -I = Includes (headers, compile time), -L = Library path, -l = link against library. When you see a "No such file or directory" error for a .hpp, always reach for -I.
- Which action addresses the stage that is now failing?
Answer: Configure a runtime library search path, such as an rpath or an appropriate loader environment path.
When troubleshooting Linux build and runtime errors, always identify which stage of the toolchain is failing. There are two distinct stages: compile/link time (when g++ runs) and runtime (when the OS loader launches your program). The question tells you the build succeeded — so the compile/link stage is fine. The failure happens at launch, meaning the dynamic linker (ld.so) can't find libgeo.so when the program actually runs.
Option B is correct because it targets exactly that failing stage. The -L flag only tells the compiler where to find libraries during linking — it has no effect at runtime. To tell the dynamic linker where to search, you need a runtime path mechanism: either an rpath baked into the binary (e.g., -Wl,-rpath,/opt/geo/lib added to your build command) or an environment variable like LD_LIBRARY_PATH=/opt/geo/lib. Both solutions inform the loader at the stage that's actually broken.
Option A is wrong because -I flags control header file search paths during compilation — they are completely irrelevant to the runtime loader, which knows nothing about C++ declarations.
Option C is a nonsense option designed to test whether you understand that #include is a preprocessor directive for source-code headers, not a way to embed or reference shared libraries.
Option D is wrong because the position of -L in the compiler command doesn't change its meaning — it will never become a runtime setting regardless of placement. -L is fundamentally a link-time-only option.
A useful mental model: think of -I and -L as compiler hints that disappear after the binary is built. Anything the running program needs must be configured separately through rpaths or loader environment variables.
- Which modification places the library-related options in the phase where they are needed?
Answer: Use g++ monitor.o -L/opt/telemetry/lib -ltelemetry -o monitor for the final command.
When building a C++ program from a shared library, it helps to think of the build process as two distinct phases: compilation (turning .cpp files into .o object files) and linking (combining object files into an executable). Each phase needs different information from you.
The compiler only needs to know declarations — what functions and types exist — which come from header files via -I flags. The linker, on the other hand, needs to know where the actual implementation lives, which means pointing it to library files using -L (search path) and -l (library name) flags. In your scenario, monitor.cpp compiled fine because the header in /opt/telemetry/include provided the necessary declarations. The link step failed because the linker never found libtelemetry.so. The fix is exactly what B does: g++ monitor.o -L/opt/telemetry/lib -ltelemetry -o monitor tells the linker where to search (-L) and which library to link (-ltelemetry), resolving the undefined reference.
A is wrong because -L and -ltelemetry placed on the compilation command (the -c step) are silently ignored — the linker isn't invoked at that stage, so the flags accomplish nothing useful.
C confuses -I (header search path) with a library path. Adding -I/opt/telemetry/lib points the compiler at the wrong directory and still provides no implementation to the linker.
D is wrong because passing a header file as direct input to the link step makes no sense — the linker works with object files and libraries, not source or header files.
A useful rule of thumb: **-I feeds the compiler; -L/-l feed the linker.** Misplacing these flags is one of the most common build errors you'll encounter in practice.