<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ro">
	<id>http://wiki.dcae.pub.ro/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rhobincu</id>
	<title>WikiLabs - Contribuții utilizator [ro]</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.dcae.pub.ro/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rhobincu"/>
	<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php/Special:Contribu%C8%9Bii/Rhobincu"/>
	<updated>2026-06-18T13:45:55Z</updated>
	<subtitle>Contribuții utilizator</subtitle>
	<generator>MediaWiki 1.35.14</generator>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_9&amp;diff=8350</id>
		<title>SDPT Lab 9</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_9&amp;diff=8350"/>
		<updated>2026-05-18T15:38:13Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 9 Lab Activity: Dynamic Analysis with Sanitizers and Valgrind =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
&lt;br /&gt;
Extend your Oven Controller&amp;#039;s CI pipeline with a fourth quality gate: a &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage that builds the project under AddressSanitizer and UndefinedBehaviorSanitizer and runs your full test suite against the instrumented binary. By the end of this lab, your pipeline catches a fourth class of bug - runtime memory errors and undefined behavior - automatically on every push.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
You will add a new CMake build type called &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; that compiles with &amp;lt;code&amp;gt;-fsanitize=address,undefined&amp;lt;/code&amp;gt; alongside &amp;lt;code&amp;gt;-O1 -g -fno-omit-frame-pointer&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;-O1&amp;lt;/code&amp;gt; keeps the optimizer light enough that sanitizer reports stay readable; &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; embeds debug information so backtraces have line numbers; &amp;lt;code&amp;gt;-fno-omit-frame-pointer&amp;lt;/code&amp;gt; ensures those backtraces are actually complete on x86_64.&lt;br /&gt;
&lt;br /&gt;
The sanitizers report errors by printing to stderr and exiting with a nonzero status. This means your existing GoogleTest tests do not need any modification: if a test triggers a sanitizer error, the test binary aborts, ctest reports failure, the CI job fails, and the MR is blocked. The pipeline plumbing from Week 6 carries this work for you for free.&lt;br /&gt;
&lt;br /&gt;
In addition to the sanitizer build, you will run Valgrind manually once against the same codebase. The two tools are complementary: ASan is fast and runs in CI; Valgrind is slow but sometimes catches things ASan misses (notably uninitialized reads, which require MemorySanitizer to catch with sanitizers - and you saw in the lecture why MSan is impractical).&lt;br /&gt;
&lt;br /&gt;
You will also reuse &amp;lt;code&amp;gt;gcovr&amp;lt;/code&amp;gt; from Week 4. Dynamic analysis can only find bugs on code paths your tests actually execute, so coverage is part of the deliverable.&lt;br /&gt;
&lt;br /&gt;
The point of this lab is not to introduce new tools you have never seen - you have met all four (ASan/UBSan/Valgrind/gcovr) in lectures. The point is to wire them together into your existing pipeline and prove the wiring works by deliberately breaking things.&lt;br /&gt;
&lt;br /&gt;
Documentation pointers: &amp;lt;code&amp;gt;man valgrind&amp;lt;/code&amp;gt;, the AddressSanitizer wiki at https://github.com/google/sanitizers/wiki/AddressSanitizer, the UBSan documentation at https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html, and your existing gcovr docs.&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Work on a feature branch opened from a tracked Issue. Open a Merge Request when you are ready to integrate.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Extend the Docker build environment.&amp;#039;&amp;#039;&amp;#039; Update your &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; to install &amp;lt;code&amp;gt;valgrind&amp;lt;/code&amp;gt; alongside the tools already present. Rebuild and verify with &amp;lt;code&amp;gt;valgrind --version&amp;lt;/code&amp;gt;. The sanitizers themselves ship with the compiler, so no separate package is needed - but confirm by running &amp;lt;code&amp;gt;echo &amp;quot;int main(){}&amp;quot; | g++ -fsanitize=address -x c++ - -o /dev/null&amp;lt;/code&amp;gt; inside the container; if that succeeds, ASan is available.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add the Sanitize build type to CMake.&amp;#039;&amp;#039;&amp;#039; In your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;, add logic that, when &amp;lt;code&amp;gt;CMAKE_BUILD_TYPE&amp;lt;/code&amp;gt; equals &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt;, sets compile and link options for &amp;lt;code&amp;gt;-fsanitize=address,undefined&amp;lt;/code&amp;gt; plus &amp;lt;code&amp;gt;-O1 -g -fno-omit-frame-pointer&amp;lt;/code&amp;gt;. Make sure both compile &amp;#039;&amp;#039;and&amp;#039;&amp;#039; link options include the sanitizer flag - if you forget the link side, you will get cryptic linker errors about missing &amp;lt;code&amp;gt;__asan_*&amp;lt;/code&amp;gt; symbols. Test locally: &amp;lt;code&amp;gt;cmake -B build-san -DCMAKE_BUILD_TYPE=Sanitize&amp;lt;/code&amp;gt;, then build, then run a test binary directly to confirm it produces output that mentions ASan.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Run your existing tests under the sanitizers and clean up.&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;ctest --test-dir build-san --output-on-failure&amp;lt;/code&amp;gt;. If any tests fail due to sanitizer reports, fix the underlying bugs in the Oven Controller code (do &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; suppress them). Typical findings in EE-trained codebases: forgotten &amp;lt;code&amp;gt;delete[]&amp;lt;/code&amp;gt;, signed overflow in temperature math, reading from a member variable that was never initialized in a constructor. Each fix should be its own small commit with a message describing what the sanitizer reported.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add a sanitize stage to GitLab CI.&amp;#039;&amp;#039;&amp;#039; Edit &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to add a new &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage after &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;. The job should: configure a &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; build, compile it, and run &amp;lt;code&amp;gt;ctest&amp;lt;/code&amp;gt; against it. Use your existing Docker image. The job must fail the pipeline on any sanitizer error.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger ASan on purpose.&amp;#039;&amp;#039;&amp;#039; On your feature branch, introduce a deliberate &amp;#039;&amp;#039;&amp;#039;heap-buffer-overflow&amp;#039;&amp;#039;&amp;#039; bug somewhere in the production code. Push, watch the &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage fail, capture the ASan report (the job-log permalink in the MR description is sufficient), then revert. Your goal is to see the full ASan diagnostic - the line with the offending access, the line of the allocation, and the &amp;quot;stack-buffer-overflow&amp;quot; or &amp;quot;heap-buffer-overflow&amp;quot; classification.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger UBSan on purpose.&amp;#039;&amp;#039;&amp;#039; Repeat with a deliberate &amp;#039;&amp;#039;&amp;#039;signed integer overflow&amp;#039;&amp;#039;&amp;#039; or &amp;#039;&amp;#039;&amp;#039;null pointer dereference&amp;#039;&amp;#039;&amp;#039;. The UBSan report looks different from ASan&amp;#039;s - a one-line &amp;quot;runtime error&amp;quot; message at the trigger point. Capture, revert.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger LeakSanitizer on purpose.&amp;#039;&amp;#039;&amp;#039; Repeat with a deliberate memory leak (allocate something on the heap, do not free it). LeakSan reports at program exit, not at the leak site. Capture, revert.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Run Valgrind once, manually.&amp;#039;&amp;#039;&amp;#039; Build your project in a normal Debug configuration (no sanitizers - they conflict with Valgrind&amp;#039;s instrumentation). From inside your Docker container, run &amp;lt;code&amp;gt;valgrind --leak-check=full --show-leakkinds=all --track-origins=yes ./your_test_binary&amp;lt;/code&amp;gt;. Save the full output. If Valgrind reports any errors that ASan did not, fix them. Add a paragraph to your MR description noting which tool caught what, or that the two agreed completely.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Re-check coverage.&amp;#039;&amp;#039;&amp;#039; Recall from Week 4: &amp;lt;code&amp;gt;gcovr -r .. --html-details&amp;lt;/code&amp;gt; against a coverage-instrumented build. Generate a current coverage report. Compare against your Week 4 baseline. If coverage dropped, write enough additional tests to bring it back. Coverage gaps are places where sanitizer findings are silently impossible, so this is part of the dynamic-analysis story even if the tool is the same one you used in Week 4.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Document the cost.&amp;#039;&amp;#039;&amp;#039; Compare the wall-clock time of your full pipeline before and after this lab. The &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage adds work; document by how much in your MR description. As in Week 7, &amp;quot;the sanitize stage adds 6 minutes and we caught two real bugs&amp;quot; is a more honest finding than rounding to &amp;quot;negligible&amp;quot;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Review and merge.&amp;#039;&amp;#039;&amp;#039; Open the MR. The reviewer should check: the Sanitize build type works locally and in CI, that the three deliberate-bug pipeline runs are visible, that the Valgrind output is referenced in the MR, that coverage has not regressed.&lt;br /&gt;
&lt;br /&gt;
== Stretch tasks (optional, if you finish early) ==&lt;br /&gt;
&lt;br /&gt;
Pick at most one. None earn extra points; all teach you something useful.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Add a second sanitizer build.&amp;#039;&amp;#039;&amp;#039; Some teams maintain two CI jobs: one with ASan+UBSan, one with ThreadSanitizer. Add a TSan job that builds with &amp;lt;code&amp;gt;-fsanitize=thread&amp;lt;/code&amp;gt; and runs the tests. Even on single-threaded code this is harmless, and it sets you up for the day you add concurrency.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Valgrind in CI.&amp;#039;&amp;#039;&amp;#039; Add a manual-trigger CI job (using GitLab&amp;#039;s &amp;lt;code&amp;gt;when: manual&amp;lt;/code&amp;gt;) that runs Valgrind on your test binary. It is too slow to run on every push, but a one-click button for the weekly deep audit is valuable.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Coverage threshold gate.&amp;#039;&amp;#039;&amp;#039; Use &amp;lt;code&amp;gt;gcovr --fail-under-line N&amp;lt;/code&amp;gt; to fail the pipeline if line coverage drops below a threshold you choose (e.g. 80%). Now coverage is also an automatic quality gate, not just a number.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sanitizer-specific environment variables.&amp;#039;&amp;#039;&amp;#039; Read the docs for &amp;lt;code&amp;gt;ASAN_OPTIONS&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UBSAN_OPTIONS&amp;lt;/code&amp;gt;. Add &amp;lt;code&amp;gt;halt_on_error=1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;abort_on_error=1&amp;lt;/code&amp;gt; to your CI environment, which makes the first error a hard stop instead of letting the program limp on. Useful for getting clearer reports.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
For this lab to be considered complete, your &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch must contain:&lt;br /&gt;
&lt;br /&gt;
# A &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; that installs &amp;lt;code&amp;gt;valgrind&amp;lt;/code&amp;gt; in addition to the previous week&amp;#039;s tooling.&lt;br /&gt;
# A &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; with a working &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; build type.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage running after the &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
# A merged Merge Request whose linked Issue (or MR description) contains:&lt;br /&gt;
## References to &amp;#039;&amp;#039;&amp;#039;three&amp;#039;&amp;#039;&amp;#039; failed pipeline runs from Tasks 5, 6, and 7 (one each for ASan, UBSan, and LeakSan), with the relevant snippet of each sanitizer&amp;#039;s report quoted briefly.&lt;br /&gt;
## The Valgrind output from Task 8, or a permalink to it (a job artifact or a gist).&lt;br /&gt;
## A note comparing Valgrind&amp;#039;s findings with the sanitizers&amp;#039; findings (Task 8).&lt;br /&gt;
## The coverage comparison from Task 9 (before/after, plus what you did about it).&lt;br /&gt;
## The pipeline cost comparison from Task 10.&lt;br /&gt;
&lt;br /&gt;
The VPL deliverables include the first three files which will be the only ones graded.&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Linker errors mentioning &amp;lt;code&amp;gt;__asan_*&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;__ubsan_*&amp;lt;/code&amp;gt; symbols.&amp;#039;&amp;#039;&amp;#039; You set the sanitizer flag for compilation but forgot to also pass it at the link step. In CMake, both &amp;lt;code&amp;gt;add_compile_options&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;add_link_options&amp;lt;/code&amp;gt; need &amp;lt;code&amp;gt;-fsanitize=...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sanitizers and Valgrind conflict.&amp;#039;&amp;#039;&amp;#039; You cannot run a sanitizer-built binary under Valgrind. They both rely on intercepting memory accesses and the interception clashes. Build a separate Debug binary (no sanitizers) when you want to run Valgrind.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ASan reports look truncated or have &amp;lt;code&amp;gt;??&amp;lt;/code&amp;gt; in the backtrace.&amp;#039;&amp;#039;&amp;#039; Almost always means missing &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; or missing &amp;lt;code&amp;gt;-fno-omit-frame-pointer&amp;lt;/code&amp;gt;. Without frame pointers, the unwinder on x86_64 falls back to imperfect heuristics.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The pipeline passes locally but ASan errors only appear in CI.&amp;#039;&amp;#039;&amp;#039; Check that your container image is using a recent enough compiler. GCC&amp;#039;s ASan got significantly better between 8.x and 11.x; UBSan added several checks in the same span. The Debian Bookworm &amp;lt;code&amp;gt;g++&amp;lt;/code&amp;gt; (12.x) is fine.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tests pass under the sanitizers locally, but a teammate&amp;#039;s machine shows different errors.&amp;#039;&amp;#039;&amp;#039; ASan and UBSan are deterministic for a given binary, but slight platform differences (libc version, glibc malloc settings) can occasionally surface bugs that are real but only fire on one machine. The CI container is the source of truth.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Valgrind reports complaints in the standard library.&amp;#039;&amp;#039;&amp;#039; Usually you can ignore these unless they reference your own code. Use &amp;lt;code&amp;gt;--suppressions=/usr/share/valgrind/default.supp&amp;lt;/code&amp;gt; (most distributions ship a default suppression file) to filter out the well-known libc and libstdc++ noise.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ASan says &amp;quot;AddressSanitizer: DEADLYSIGNAL&amp;quot; with no obvious cause.&amp;#039;&amp;#039;&amp;#039; Your program received a fatal signal (often SIGSEGV) inside ASan&amp;#039;s own instrumentation. This usually means very serious memory corruption or stack overflow. Use &amp;lt;code&amp;gt;ASAN_OPTIONS=abort_on_error=1&amp;lt;/code&amp;gt; to get a core dump and a clearer backtrace.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Some sanitizer findings disappear at &amp;lt;code&amp;gt;-O2&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;.&amp;#039;&amp;#039;&amp;#039; That is expected - the optimizer can eliminate the offending construct entirely. Keep your sanitizer build at &amp;lt;code&amp;gt;-O1&amp;lt;/code&amp;gt;: optimized enough to be realistic, unoptimized enough to keep reports trustworthy.&lt;br /&gt;
&lt;br /&gt;
== Looking ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week: &amp;#039;&amp;#039;&amp;#039;Documentation as Code&amp;#039;&amp;#039;&amp;#039;. You will add a Doxygen build to your CMake, publish the generated HTML docs as a GitLab Pages artifact, and turn your scattered code comments into navigable API documentation. Bring a piece of your capstone code that is poorly documented and you want to improve.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_10&amp;diff=8349</id>
		<title>SDPT Lab 10</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_10&amp;diff=8349"/>
		<updated>2026-05-18T13:50:45Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 10 Lab Activity: Documentation as Code with Doxygen =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
&lt;br /&gt;
Generate API documentation for your Oven Controller with Doxygen and publish it automatically to GitLab Pages. This lab is deliberately short --- once the documentation pipeline works, the rest of the session is yours for capstone work.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
Doxygen parses your source code and your specially-formatted comments and produces a cross-referenced HTML website. It is configured by a single file, the &amp;#039;&amp;#039;&amp;#039;Doxyfile&amp;#039;&amp;#039;&amp;#039;, generated with &amp;lt;code&amp;gt;doxygen -g&amp;lt;/code&amp;gt;. Because Doxygen reads source directly, it needs no compiled binary --- the documentation job does not depend on your &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; stage at all, and in this lab it runs &amp;lt;code&amp;gt;doxygen Doxyfile&amp;lt;/code&amp;gt; directly without involving CMake. (You &amp;#039;&amp;#039;can&amp;#039;&amp;#039; add a &amp;lt;code&amp;gt;docs&amp;lt;/code&amp;gt; target to &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; that wraps the same command, as the lecture notes, but this lab does not require it.)&lt;br /&gt;
&lt;br /&gt;
GitLab Pages serves a static website straight from a CI job. On this course&amp;#039;s instance, &amp;lt;code&amp;gt;gitlab.cs.pub.ro&amp;lt;/code&amp;gt;, the Pages wildcard domain is &amp;lt;code&amp;gt;pages.upb.ro&amp;lt;/code&amp;gt;. With unique domains enabled (the default), your published site receives an unpredictable URL of the form &amp;lt;code&amp;gt;https://&amp;amp;lt;project&amp;amp;gt;-&amp;amp;lt;6-char-id&amp;amp;gt;.pages.upb.ro/&amp;lt;/code&amp;gt;. You read the exact URL from &amp;#039;&amp;#039;&amp;#039;Deploy &amp;amp;gt; Pages&amp;#039;&amp;#039;&amp;#039; in the GitLab UI after the first successful deployment --- you cannot know it in advance.&lt;br /&gt;
&lt;br /&gt;
The modern GitLab Pages CI syntax marks a job as a Pages job using a &amp;lt;code&amp;gt;pages:&amp;lt;/code&amp;gt; property, and names the directory to publish using &amp;lt;code&amp;gt;publish:&amp;lt;/code&amp;gt; inside it. The job itself can have any name. See the Week 10 lecture slide &amp;quot;CI Integration: Publishing to GitLab Pages&amp;quot; for the shape of this job.&lt;br /&gt;
&lt;br /&gt;
For Doxygen comment syntax, see the lecture&amp;#039;s before/after Oven Controller slides. Reference material: the Doxygen manual at https://www.doxygen.nl/manual/, and the special-command list at https://www.doxygen.nl/manual/commands.html.&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Work on a feature branch opened from a tracked Issue. Open a Merge Request when you are ready to integrate.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Generate the Doxyfile.&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;doxygen -g&amp;lt;/code&amp;gt; in your project root. This creates a file named &amp;lt;code&amp;gt;Doxyfile&amp;lt;/code&amp;gt; containing every Doxygen setting with its default value and an explanatory comment. Commit it as-is in its own commit, so your later configuration changes are visible as a clean diff.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Configure the Doxyfile.&amp;#039;&amp;#039;&amp;#039; Edit at least the following settings: &amp;lt;code&amp;gt;PROJECT_NAME&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PROJECT_NUMBER&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;INPUT&amp;lt;/code&amp;gt; (point it at your source and header directories and your &amp;lt;code&amp;gt;README.md&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;RECURSIVE = YES&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;EXTRACT_ALL = YES&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;GENERATE_HTML = YES&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;GENERATE_LATEX = NO&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;HAVE_DOT = YES&amp;lt;/code&amp;gt; (enables the Graphviz class and call diagrams); and &amp;lt;code&amp;gt;USE_MDFILE_AS_MAINPAGE&amp;lt;/code&amp;gt; (set to your &amp;lt;code&amp;gt;README.md&amp;lt;/code&amp;gt; so it becomes the documentation landing page). Leave &amp;lt;code&amp;gt;OUTPUT_DIRECTORY&amp;lt;/code&amp;gt; empty and &amp;lt;code&amp;gt;HTML_OUTPUT&amp;lt;/code&amp;gt; at its default &amp;lt;code&amp;gt;html&amp;lt;/code&amp;gt;, so the generated site lands in &amp;lt;code&amp;gt;./html&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Document the Oven Controller&amp;#039;s public API.&amp;#039;&amp;#039;&amp;#039; Add Doxygen comments to the main class and its public methods. Each public function should have a &amp;lt;code&amp;gt;\brief&amp;lt;/code&amp;gt;, plus &amp;lt;code&amp;gt;\param&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;\return&amp;lt;/code&amp;gt; where they apply. Write genuine contracts --- units, valid ranges, error behavior --- not restatements of the function name. The lecture&amp;#039;s before/after example sets the standard. &amp;#039;&amp;#039;This task is verified through your published documentation site, not submitted as a file.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Build and check locally.&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;doxygen Doxyfile&amp;lt;/code&amp;gt;. Open &amp;lt;code&amp;gt;html/index.html&amp;lt;/code&amp;gt; in a browser and confirm that your classes, your comments, and (if Graphviz is installed locally) the diagrams all appear as expected. Fix anything that looks wrong before moving on.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add the documentation job to CI.&amp;#039;&amp;#039;&amp;#039; Edit &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt;:&lt;br /&gt;
## Add a new &amp;lt;code&amp;gt;docs&amp;lt;/code&amp;gt; stage as the last stage.&lt;br /&gt;
## Add a job (suggested name &amp;lt;code&amp;gt;create-pages&amp;lt;/code&amp;gt;) in that stage. It should use a stock Debian or Ubuntu image, install &amp;lt;code&amp;gt;doxygen&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;graphviz&amp;lt;/code&amp;gt; in a &amp;lt;code&amp;gt;before_script&amp;lt;/code&amp;gt;, run &amp;lt;code&amp;gt;doxygen Doxyfile&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;script&amp;lt;/code&amp;gt;, and publish the &amp;lt;code&amp;gt;html&amp;lt;/code&amp;gt; directory using the &amp;lt;code&amp;gt;pages:&amp;lt;/code&amp;gt; property.&lt;br /&gt;
## Restrict the job to the default branch with a &amp;lt;code&amp;gt;rules:&amp;lt;/code&amp;gt; entry, so the documentation deploys only from released code.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Publish and verify.&amp;#039;&amp;#039;&amp;#039; Push your branch and open the Merge Request. Note that because the job is restricted to the default branch, it will &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; run on your feature-branch pipeline --- this is expected. Once the MR is merged, the pipeline on the default branch runs the &amp;lt;code&amp;gt;create-pages&amp;lt;/code&amp;gt; job. Then open &amp;#039;&amp;#039;&amp;#039;Deploy &amp;amp;gt; Pages&amp;#039;&amp;#039;&amp;#039;, find your site&amp;#039;s live URL, open it, and confirm the documentation is served correctly. Paste that URL into your Merge Request description.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
Submit exactly two files:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;Doxyfile&amp;lt;/code&amp;gt; --- your configured Doxygen configuration file.&lt;br /&gt;
# &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; --- including the new &amp;lt;code&amp;gt;docs&amp;lt;/code&amp;gt; stage and the &amp;lt;code&amp;gt;create-pages&amp;lt;/code&amp;gt; job.&lt;br /&gt;
&lt;br /&gt;
In addition, your Merge Request description must contain the live GitLab Pages URL from Task 6. The quality of your Doxygen comments (Task 3) is assessed by visiting that URL.&lt;br /&gt;
&lt;br /&gt;
== Stretch tasks (optional) ==&lt;br /&gt;
&lt;br /&gt;
Pick at most one. Neither earns extra points; both make your capstone documentation noticeably better.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Turn documentation into a real gate.&amp;#039;&amp;#039;&amp;#039; Set &amp;lt;code&amp;gt;EXTRACT_ALL = NO&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WARN_IF_UNDOCUMENTED = YES&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;WARN_AS_ERROR = YES&amp;lt;/code&amp;gt; in your Doxyfile. Now Doxygen exits with an error --- failing the pipeline --- whenever a public entity has no documentation. Then document everything until the job passes. This is how documentation becomes a true quality gate rather than a suggestion.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Add a hand-written architecture page.&amp;#039;&amp;#039;&amp;#039; Create &amp;lt;code&amp;gt;docs/architecture.md&amp;lt;/code&amp;gt; describing how the Oven Controller&amp;#039;s pieces fit together. Add it to the Doxyfile&amp;#039;s &amp;lt;code&amp;gt;INPUT&amp;lt;/code&amp;gt;. It will appear as a first-class page in your documentation site, alongside the auto-extracted API reference.&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The published site is 404 or shows the wrong content.&amp;#039;&amp;#039;&amp;#039; The directory named in &amp;lt;code&amp;gt;publish:&amp;lt;/code&amp;gt; must exactly match where Doxygen actually wrote the HTML. With the default &amp;lt;code&amp;gt;HTML_OUTPUT = html&amp;lt;/code&amp;gt; and an empty &amp;lt;code&amp;gt;OUTPUT_DIRECTORY&amp;lt;/code&amp;gt;, that directory is &amp;lt;code&amp;gt;html&amp;lt;/code&amp;gt;. If you changed either setting, update &amp;lt;code&amp;gt;publish:&amp;lt;/code&amp;gt; to match.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The docs job never runs.&amp;#039;&amp;#039;&amp;#039; If you restricted it to the default branch, it will not appear on feature-branch or Merge Request pipelines --- only after the merge. This is correct behavior. Verify the &amp;lt;code&amp;gt;doxygen&amp;lt;/code&amp;gt; command itself locally (Task 4) so you are confident before merging.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The &amp;lt;code&amp;gt;pages:&amp;lt;/code&amp;gt; keyword causes a YAML or pipeline error.&amp;#039;&amp;#039;&amp;#039; The Pages CI syntax has changed across GitLab versions. The &amp;lt;code&amp;gt;pages:&amp;lt;/code&amp;gt; property with &amp;lt;code&amp;gt;publish:&amp;lt;/code&amp;gt; inside it is the current form. If your instance rejects it, check the GitLab version of &amp;lt;code&amp;gt;gitlab.cs.pub.ro&amp;lt;/code&amp;gt; and consult its documentation for the exact accepted syntax.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;No diagrams in the output.&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;HAVE_DOT = YES&amp;lt;/code&amp;gt; requires the Graphviz &amp;lt;code&amp;gt;dot&amp;lt;/code&amp;gt; tool to be installed. Make sure your CI &amp;lt;code&amp;gt;before_script&amp;lt;/code&amp;gt; installs &amp;lt;code&amp;gt;graphviz&amp;lt;/code&amp;gt;, not only &amp;lt;code&amp;gt;doxygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Doxygen reports warnings about undocumented members.&amp;#039;&amp;#039;&amp;#039; With &amp;lt;code&amp;gt;EXTRACT_ALL = YES&amp;lt;/code&amp;gt; this is harmless --- the site still builds. It only fails the job if you also set &amp;lt;code&amp;gt;WARN_AS_ERROR = YES&amp;lt;/code&amp;gt; (see the stretch task).&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;I cannot find my Pages URL.&amp;#039;&amp;#039;&amp;#039; It is under &amp;#039;&amp;#039;&amp;#039;Deploy &amp;amp;gt; Pages&amp;#039;&amp;#039;&amp;#039; in the GitLab project sidebar, and only appears after the &amp;lt;code&amp;gt;create-pages&amp;lt;/code&amp;gt; job has succeeded at least once on the default branch.&lt;br /&gt;
&lt;br /&gt;
== Looking ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week is the last: &amp;#039;&amp;#039;&amp;#039;Capstone Synthesis&amp;#039;&amp;#039;&amp;#039;. Your CI pipeline is now complete --- build, test, lint, sanitize, and docs. We step back, look at the whole system you have built, cover a few industry topics, and reserve lab time for capstone polish and a dry run of your project presentation.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_10&amp;diff=8348</id>
		<title>SDPT Lab 10</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_10&amp;diff=8348"/>
		<updated>2026-05-18T13:48:36Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: = Week 10 Lab Activity: Documentation as Code with Doxygen =  == Objective ==  Generate API documentation for your Oven Controller with Doxygen and publish it automatically to GitL...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 10 Lab Activity: Documentation as Code with Doxygen =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
&lt;br /&gt;
Generate API documentation for your Oven Controller with Doxygen and publish it automatically to GitLab Pages. This lab is deliberately short --- once the documentation pipeline works, the rest of the session is yours for capstone work.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
Doxygen parses your source code and your specially-formatted comments and produces a cross-referenced HTML website. It is configured by a single file, the &amp;#039;&amp;#039;&amp;#039;Doxyfile&amp;#039;&amp;#039;&amp;#039;, generated with &amp;lt;code&amp;gt;doxygen -g&amp;lt;/code&amp;gt;. Because Doxygen reads source directly, it needs no compiled binary and no CMake involvement --- the documentation job is completely independent of your build.&lt;br /&gt;
&lt;br /&gt;
GitLab Pages serves a static website straight from a CI job. On this course&amp;#039;s instance, &amp;lt;code&amp;gt;gitlab.cs.pub.ro&amp;lt;/code&amp;gt;, the Pages wildcard domain is &amp;lt;code&amp;gt;pages.upb.ro&amp;lt;/code&amp;gt;. With unique domains enabled (the default), your published site receives an unpredictable URL of the form &amp;lt;code&amp;gt;https://&amp;amp;lt;project&amp;amp;gt;-&amp;amp;lt;6-char-id&amp;amp;gt;.pages.upb.ro/&amp;lt;/code&amp;gt;. You read the exact URL from &amp;#039;&amp;#039;&amp;#039;Deploy &amp;amp;gt; Pages&amp;#039;&amp;#039;&amp;#039; in the GitLab UI after the first successful deployment --- you cannot know it in advance.&lt;br /&gt;
&lt;br /&gt;
The modern GitLab Pages CI syntax marks a job as a Pages job using a &amp;lt;code&amp;gt;pages:&amp;lt;/code&amp;gt; property, and names the directory to publish using &amp;lt;code&amp;gt;publish:&amp;lt;/code&amp;gt; inside it. The job itself can have any name. See the Week 10 lecture slide &amp;quot;CI Integration: Publishing to GitLab Pages&amp;quot; for the shape of this job.&lt;br /&gt;
&lt;br /&gt;
For Doxygen comment syntax, see the lecture&amp;#039;s before/after Oven Controller slides. Reference material: the Doxygen manual at https://www.doxygen.nl/manual/, and the special-command list at https://www.doxygen.nl/manual/commands.html.&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Work on a feature branch opened from a tracked Issue. Open a Merge Request when you are ready to integrate.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Generate the Doxyfile.&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;doxygen -g&amp;lt;/code&amp;gt; in your project root. This creates a file named &amp;lt;code&amp;gt;Doxyfile&amp;lt;/code&amp;gt; containing every Doxygen setting with its default value and an explanatory comment. Commit it as-is in its own commit, so your later configuration changes are visible as a clean diff.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Configure the Doxyfile.&amp;#039;&amp;#039;&amp;#039; Edit at least the following settings: &amp;lt;code&amp;gt;PROJECT_NAME&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PROJECT_NUMBER&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;INPUT&amp;lt;/code&amp;gt; (point it at your source and header directories and your &amp;lt;code&amp;gt;README.md&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;RECURSIVE = YES&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;EXTRACT_ALL = YES&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;GENERATE_HTML = YES&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;GENERATE_LATEX = NO&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;HAVE_DOT = YES&amp;lt;/code&amp;gt; (enables the Graphviz class and call diagrams); and &amp;lt;code&amp;gt;USE_MDFILE_AS_MAINPAGE&amp;lt;/code&amp;gt; (set to your &amp;lt;code&amp;gt;README.md&amp;lt;/code&amp;gt; so it becomes the documentation landing page). Leave &amp;lt;code&amp;gt;OUTPUT_DIRECTORY&amp;lt;/code&amp;gt; empty and &amp;lt;code&amp;gt;HTML_OUTPUT&amp;lt;/code&amp;gt; at its default &amp;lt;code&amp;gt;html&amp;lt;/code&amp;gt;, so the generated site lands in &amp;lt;code&amp;gt;./html&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Document the Oven Controller&amp;#039;s public API.&amp;#039;&amp;#039;&amp;#039; Add Doxygen comments to the main class and its public methods. Each public function should have a &amp;lt;code&amp;gt;\brief&amp;lt;/code&amp;gt;, plus &amp;lt;code&amp;gt;\param&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;\return&amp;lt;/code&amp;gt; where they apply. Write genuine contracts --- units, valid ranges, error behavior --- not restatements of the function name. The lecture&amp;#039;s before/after example sets the standard. &amp;#039;&amp;#039;This task is verified through your published documentation site, not submitted as a file.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Build and check locally.&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;doxygen Doxyfile&amp;lt;/code&amp;gt;. Open &amp;lt;code&amp;gt;html/index.html&amp;lt;/code&amp;gt; in a browser and confirm that your classes, your comments, and (if Graphviz is installed locally) the diagrams all appear as expected. Fix anything that looks wrong before moving on.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add the documentation job to CI.&amp;#039;&amp;#039;&amp;#039; Edit &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt;:&lt;br /&gt;
## Add a new &amp;lt;code&amp;gt;docs&amp;lt;/code&amp;gt; stage as the last stage.&lt;br /&gt;
## Add a job (suggested name &amp;lt;code&amp;gt;create-pages&amp;lt;/code&amp;gt;) in that stage. It should use a stock Debian or Ubuntu image, install &amp;lt;code&amp;gt;doxygen&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;graphviz&amp;lt;/code&amp;gt; in a &amp;lt;code&amp;gt;before_script&amp;lt;/code&amp;gt;, run &amp;lt;code&amp;gt;doxygen Doxyfile&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;script&amp;lt;/code&amp;gt;, and publish the &amp;lt;code&amp;gt;html&amp;lt;/code&amp;gt; directory using the &amp;lt;code&amp;gt;pages:&amp;lt;/code&amp;gt; property.&lt;br /&gt;
## Restrict the job to the default branch with a &amp;lt;code&amp;gt;rules:&amp;lt;/code&amp;gt; entry, so the documentation deploys only from released code.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Publish and verify.&amp;#039;&amp;#039;&amp;#039; Push your branch and open the Merge Request. Note that because the job is restricted to the default branch, it will &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; run on your feature-branch pipeline --- this is expected. Once the MR is merged, the pipeline on the default branch runs the &amp;lt;code&amp;gt;create-pages&amp;lt;/code&amp;gt; job. Then open &amp;#039;&amp;#039;&amp;#039;Deploy &amp;amp;gt; Pages&amp;#039;&amp;#039;&amp;#039;, find your site&amp;#039;s live URL, open it, and confirm the documentation is served correctly. Paste that URL into your Merge Request description.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
Submit exactly two files:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;Doxyfile&amp;lt;/code&amp;gt; --- your configured Doxygen configuration file.&lt;br /&gt;
# &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; --- including the new &amp;lt;code&amp;gt;docs&amp;lt;/code&amp;gt; stage and the &amp;lt;code&amp;gt;create-pages&amp;lt;/code&amp;gt; job.&lt;br /&gt;
&lt;br /&gt;
In addition, your Merge Request description must contain the live GitLab Pages URL from Task 6. The quality of your Doxygen comments (Task 3) is assessed by visiting that URL.&lt;br /&gt;
&lt;br /&gt;
== Stretch tasks (optional) ==&lt;br /&gt;
&lt;br /&gt;
Pick at most one. Neither earns extra points; both make your capstone documentation noticeably better.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Turn documentation into a real gate.&amp;#039;&amp;#039;&amp;#039; Set &amp;lt;code&amp;gt;EXTRACT_ALL = NO&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WARN_IF_UNDOCUMENTED = YES&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;WARN_AS_ERROR = YES&amp;lt;/code&amp;gt; in your Doxyfile. Now Doxygen exits with an error --- failing the pipeline --- whenever a public entity has no documentation. Then document everything until the job passes. This is how documentation becomes a true quality gate rather than a suggestion.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Add a hand-written architecture page.&amp;#039;&amp;#039;&amp;#039; Create &amp;lt;code&amp;gt;docs/architecture.md&amp;lt;/code&amp;gt; describing how the Oven Controller&amp;#039;s pieces fit together. Add it to the Doxyfile&amp;#039;s &amp;lt;code&amp;gt;INPUT&amp;lt;/code&amp;gt;. It will appear as a first-class page in your documentation site, alongside the auto-extracted API reference.&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The published site is 404 or shows the wrong content.&amp;#039;&amp;#039;&amp;#039; The directory named in &amp;lt;code&amp;gt;publish:&amp;lt;/code&amp;gt; must exactly match where Doxygen actually wrote the HTML. With the default &amp;lt;code&amp;gt;HTML_OUTPUT = html&amp;lt;/code&amp;gt; and an empty &amp;lt;code&amp;gt;OUTPUT_DIRECTORY&amp;lt;/code&amp;gt;, that directory is &amp;lt;code&amp;gt;html&amp;lt;/code&amp;gt;. If you changed either setting, update &amp;lt;code&amp;gt;publish:&amp;lt;/code&amp;gt; to match.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The docs job never runs.&amp;#039;&amp;#039;&amp;#039; If you restricted it to the default branch, it will not appear on feature-branch or Merge Request pipelines --- only after the merge. This is correct behavior. Verify the &amp;lt;code&amp;gt;doxygen&amp;lt;/code&amp;gt; command itself locally (Task 4) so you are confident before merging.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The &amp;lt;code&amp;gt;pages:&amp;lt;/code&amp;gt; keyword causes a YAML or pipeline error.&amp;#039;&amp;#039;&amp;#039; The Pages CI syntax has changed across GitLab versions. The &amp;lt;code&amp;gt;pages:&amp;lt;/code&amp;gt; property with &amp;lt;code&amp;gt;publish:&amp;lt;/code&amp;gt; inside it is the current form. If your instance rejects it, check the GitLab version of &amp;lt;code&amp;gt;gitlab.cs.pub.ro&amp;lt;/code&amp;gt; and consult its documentation for the exact accepted syntax.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;No diagrams in the output.&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;HAVE_DOT = YES&amp;lt;/code&amp;gt; requires the Graphviz &amp;lt;code&amp;gt;dot&amp;lt;/code&amp;gt; tool to be installed. Make sure your CI &amp;lt;code&amp;gt;before_script&amp;lt;/code&amp;gt; installs &amp;lt;code&amp;gt;graphviz&amp;lt;/code&amp;gt;, not only &amp;lt;code&amp;gt;doxygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Doxygen reports warnings about undocumented members.&amp;#039;&amp;#039;&amp;#039; With &amp;lt;code&amp;gt;EXTRACT_ALL = YES&amp;lt;/code&amp;gt; this is harmless --- the site still builds. It only fails the job if you also set &amp;lt;code&amp;gt;WARN_AS_ERROR = YES&amp;lt;/code&amp;gt; (see the stretch task).&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;I cannot find my Pages URL.&amp;#039;&amp;#039;&amp;#039; It is under &amp;#039;&amp;#039;&amp;#039;Deploy &amp;amp;gt; Pages&amp;#039;&amp;#039;&amp;#039; in the GitLab project sidebar, and only appears after the &amp;lt;code&amp;gt;create-pages&amp;lt;/code&amp;gt; job has succeeded at least once on the default branch.&lt;br /&gt;
&lt;br /&gt;
== Looking ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week is the last: &amp;#039;&amp;#039;&amp;#039;Capstone Synthesis&amp;#039;&amp;#039;&amp;#039;. Your CI pipeline is now complete --- build, test, lint, sanitize, and docs. We step back, look at the whole system you have built, cover a few industry topics, and reserve lab time for capstone polish and a dry run of your project presentation.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8347</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8347"/>
		<updated>2026-05-18T13:48:30Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;br /&gt;
* [[SDPT Lab 2]]&lt;br /&gt;
* [[SDPT Lab 3]]&lt;br /&gt;
* [[SDPT Lab 4]]&lt;br /&gt;
* [[SDPT Lab 5]]&lt;br /&gt;
* [[SDPT Lab 6]]&lt;br /&gt;
* [[SDPT Lab 7]]&lt;br /&gt;
* [[SDPT Lab 8]]&lt;br /&gt;
* [[SDPT Lab 9]] &lt;br /&gt;
* [[SDPT Lab 10]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_9&amp;diff=8346</id>
		<title>SDPT Lab 9</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_9&amp;diff=8346"/>
		<updated>2026-05-11T13:41:55Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Deliverables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 9 Lab Activity: Dynamic Analysis with Sanitizers and Valgrind =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
&lt;br /&gt;
Extend your Oven Controller&amp;#039;s CI pipeline with a fourth quality gate: a &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage that builds the project under AddressSanitizer and UndefinedBehaviorSanitizer and runs your full test suite against the instrumented binary. By the end of this lab, your pipeline catches a fourth class of bug - runtime memory errors and undefined behavior - automatically on every push.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
You will add a new CMake build type called &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; that compiles with &amp;lt;code&amp;gt;-fsanitize=address,undefined&amp;lt;/code&amp;gt; alongside &amp;lt;code&amp;gt;-O1 -g -fno-omit-frame-pointer&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;-O1&amp;lt;/code&amp;gt; keeps the optimizer light enough that sanitizer reports stay readable; &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; embeds debug information so backtraces have line numbers; &amp;lt;code&amp;gt;-fno-omit-frame-pointer&amp;lt;/code&amp;gt; ensures those backtraces are actually complete on x86_64.&lt;br /&gt;
&lt;br /&gt;
The sanitizers report errors by printing to stderr and exiting with a nonzero status. This means your existing GoogleTest tests do not need any modification: if a test triggers a sanitizer error, the test binary aborts, ctest reports failure, the CI job fails, and the MR is blocked. The pipeline plumbing from Week 6 carries this work for you for free.&lt;br /&gt;
&lt;br /&gt;
In addition to the sanitizer build, you will run Valgrind manually once against the same codebase. The two tools are complementary: ASan is fast and runs in CI; Valgrind is slow but sometimes catches things ASan misses (notably uninitialized reads, which require MemorySanitizer to catch with sanitizers - and you saw in the lecture why MSan is impractical).&lt;br /&gt;
&lt;br /&gt;
You will also reuse &amp;lt;code&amp;gt;gcovr&amp;lt;/code&amp;gt; from Week 4. Dynamic analysis can only find bugs on code paths your tests actually execute, so coverage is part of the deliverable.&lt;br /&gt;
&lt;br /&gt;
The point of this lab is not to introduce new tools you have never seen - you have met all four (ASan/UBSan/Valgrind/gcovr) in lectures. The point is to wire them together into your existing pipeline and prove the wiring works by deliberately breaking things.&lt;br /&gt;
&lt;br /&gt;
Documentation pointers: &amp;lt;code&amp;gt;man valgrind&amp;lt;/code&amp;gt;, the AddressSanitizer wiki at https://github.com/google/sanitizers/wiki/AddressSanitizer, the UBSan documentation at https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html, and your existing gcovr docs.&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Work on a feature branch opened from a tracked Issue. Open a Merge Request when you are ready to integrate.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Extend the Docker build environment.&amp;#039;&amp;#039;&amp;#039; Update your &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; to install &amp;lt;code&amp;gt;valgrind&amp;lt;/code&amp;gt; alongside the tools already present. Rebuild and verify with &amp;lt;code&amp;gt;valgrind --version&amp;lt;/code&amp;gt;. The sanitizers themselves ship with the compiler, so no separate package is needed - but confirm by running &amp;lt;code&amp;gt;echo &amp;quot;int main(){}&amp;quot; | g++ -fsanitize=address -x c++ - -o /dev/null&amp;lt;/code&amp;gt; inside the container; if that succeeds, ASan is available.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add the Sanitize build type to CMake.&amp;#039;&amp;#039;&amp;#039; In your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;, add logic that, when &amp;lt;code&amp;gt;CMAKE_BUILD_TYPE&amp;lt;/code&amp;gt; equals &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt;, sets compile and link options for &amp;lt;code&amp;gt;-fsanitize=address,undefined&amp;lt;/code&amp;gt; plus &amp;lt;code&amp;gt;-O1 -g -fno-omit-frame-pointer&amp;lt;/code&amp;gt;. Make sure both compile &amp;#039;&amp;#039;and&amp;#039;&amp;#039; link options include the sanitizer flag - if you forget the link side, you will get cryptic linker errors about missing &amp;lt;code&amp;gt;__asan_*&amp;lt;/code&amp;gt; symbols. Test locally: &amp;lt;code&amp;gt;cmake -B build-san -DCMAKE_BUILD_TYPE=Sanitize&amp;lt;/code&amp;gt;, then build, then run a test binary directly to confirm it produces output that mentions ASan.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Run your existing tests under the sanitizers and clean up.&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;ctest --test-dir build-san --output-on-failure&amp;lt;/code&amp;gt;. If any tests fail due to sanitizer reports, fix the underlying bugs in the Oven Controller code (do &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; suppress them). Typical findings in EE-trained codebases: forgotten &amp;lt;code&amp;gt;delete[]&amp;lt;/code&amp;gt;, signed overflow in temperature math, reading from a member variable that was never initialized in a constructor. Each fix should be its own small commit with a message describing what the sanitizer reported.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add a sanitize stage to GitLab CI.&amp;#039;&amp;#039;&amp;#039; Edit &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to add a new &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage after &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;. The job should: configure a &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; build, compile it, and run &amp;lt;code&amp;gt;ctest&amp;lt;/code&amp;gt; against it. Use your existing Docker image. The job must fail the pipeline on any sanitizer error.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger ASan on purpose.&amp;#039;&amp;#039;&amp;#039; On your feature branch, introduce a deliberate &amp;#039;&amp;#039;&amp;#039;heap-buffer-overflow&amp;#039;&amp;#039;&amp;#039; bug somewhere in the production code. Push, watch the &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage fail, capture the ASan report (the job-log permalink in the MR description is sufficient), then revert. Your goal is to see the full ASan diagnostic - the line with the offending access, the line of the allocation, and the &amp;quot;stack-buffer-overflow&amp;quot; or &amp;quot;heap-buffer-overflow&amp;quot; classification.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger UBSan on purpose.&amp;#039;&amp;#039;&amp;#039; Repeat with a deliberate &amp;#039;&amp;#039;&amp;#039;signed integer overflow&amp;#039;&amp;#039;&amp;#039; or &amp;#039;&amp;#039;&amp;#039;null pointer dereference&amp;#039;&amp;#039;&amp;#039;. The UBSan report looks different from ASan&amp;#039;s - a one-line &amp;quot;runtime error&amp;quot; message at the trigger point. Capture, revert.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger LeakSanitizer on purpose.&amp;#039;&amp;#039;&amp;#039; Repeat with a deliberate memory leak (allocate something on the heap, do not free it). LeakSan reports at program exit, not at the leak site. Capture, revert.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Run Valgrind once, manually.&amp;#039;&amp;#039;&amp;#039; Build your project in a normal Debug configuration (no sanitizers - they conflict with Valgrind&amp;#039;s instrumentation). From inside your Docker container, run &amp;lt;code&amp;gt;valgrind --leak-check=full --show-leakkinds=all --track-origins=yes ./your_test_binary&amp;lt;/code&amp;gt;. Save the full output. If Valgrind reports any errors that ASan did not, fix them. Add a paragraph to your MR description noting which tool caught what, or that the two agreed completely.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Re-check coverage.&amp;#039;&amp;#039;&amp;#039; Recall from Week 4: &amp;lt;code&amp;gt;gcovr -r .. --html-details&amp;lt;/code&amp;gt; against a coverage-instrumented build. Generate a current coverage report. Compare against your Week 4 baseline. If coverage dropped, write enough additional tests to bring it back. Coverage gaps are places where sanitizer findings are silently impossible, so this is part of the dynamic-analysis story even if the tool is the same one you used in Week 4.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Document the cost.&amp;#039;&amp;#039;&amp;#039; Compare the wall-clock time of your full pipeline before and after this lab. The &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage adds work; document by how much in your MR description. As in Week 7, &amp;quot;the sanitize stage adds 6 minutes and we caught two real bugs&amp;quot; is a more honest finding than rounding to &amp;quot;negligible&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Review and merge.&amp;#039;&amp;#039;&amp;#039; Open the MR. The reviewer should check: the Sanitize build type works locally and in CI, that the three deliberate-bug pipeline runs are visible, that the Valgrind output is referenced in the MR, that coverage has not regressed.&lt;br /&gt;
&lt;br /&gt;
== Stretch tasks (optional, if you finish early) ==&lt;br /&gt;
&lt;br /&gt;
Pick at most one. None earn extra points; all teach you something useful.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Add a second sanitizer build.&amp;#039;&amp;#039;&amp;#039; Some teams maintain two CI jobs: one with ASan+UBSan, one with ThreadSanitizer. Add a TSan job that builds with &amp;lt;code&amp;gt;-fsanitize=thread&amp;lt;/code&amp;gt; and runs the tests. Even on single-threaded code this is harmless, and it sets you up for the day you add concurrency.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Valgrind in CI.&amp;#039;&amp;#039;&amp;#039; Add a manual-trigger CI job (using GitLab&amp;#039;s &amp;lt;code&amp;gt;when: manual&amp;lt;/code&amp;gt;) that runs Valgrind on your test binary. It is too slow to run on every push, but a one-click button for the weekly deep audit is valuable.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Coverage threshold gate.&amp;#039;&amp;#039;&amp;#039; Use &amp;lt;code&amp;gt;gcovr --fail-under-line N&amp;lt;/code&amp;gt; to fail the pipeline if line coverage drops below a threshold you choose (e.g. 80%). Now coverage is also an automatic quality gate, not just a number.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sanitizer-specific environment variables.&amp;#039;&amp;#039;&amp;#039; Read the docs for &amp;lt;code&amp;gt;ASAN_OPTIONS&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UBSAN_OPTIONS&amp;lt;/code&amp;gt;. Add &amp;lt;code&amp;gt;halt_on_error=1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;abort_on_error=1&amp;lt;/code&amp;gt; to your CI environment, which makes the first error a hard stop instead of letting the program limp on. Useful for getting clearer reports.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
For this lab to be considered complete, your &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch must contain:&lt;br /&gt;
&lt;br /&gt;
# A &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; that installs &amp;lt;code&amp;gt;valgrind&amp;lt;/code&amp;gt; in addition to the previous week&amp;#039;s tooling.&lt;br /&gt;
# A &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; with a working &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; build type.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage running after the &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
# A merged Merge Request whose linked Issue (or MR description) contains:&lt;br /&gt;
## References to &amp;#039;&amp;#039;&amp;#039;three&amp;#039;&amp;#039;&amp;#039; failed pipeline runs from Tasks 5, 6, and 7 (one each for ASan, UBSan, and LeakSan), with the relevant snippet of each sanitizer&amp;#039;s report quoted briefly.&lt;br /&gt;
## The Valgrind output from Task 8, or a permalink to it (a job artifact or a gist).&lt;br /&gt;
## A note comparing Valgrind&amp;#039;s findings with the sanitizers&amp;#039; findings (Task 8).&lt;br /&gt;
## The coverage comparison from Task 9 (before/after, plus what you did about it).&lt;br /&gt;
## The pipeline cost comparison from Task 10.&lt;br /&gt;
&lt;br /&gt;
The VPL deliverables include the first three files which will be the only ones graded.&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Linker errors mentioning &amp;lt;code&amp;gt;__asan_*&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;__ubsan_*&amp;lt;/code&amp;gt; symbols.&amp;#039;&amp;#039;&amp;#039; You set the sanitizer flag for compilation but forgot to also pass it at the link step. In CMake, both &amp;lt;code&amp;gt;add_compile_options&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;add_link_options&amp;lt;/code&amp;gt; need &amp;lt;code&amp;gt;-fsanitize=...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sanitizers and Valgrind conflict.&amp;#039;&amp;#039;&amp;#039; You cannot run a sanitizer-built binary under Valgrind. They both rely on intercepting memory accesses and the interception clashes. Build a separate Debug binary (no sanitizers) when you want to run Valgrind.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ASan reports look truncated or have &amp;lt;code&amp;gt;??&amp;lt;/code&amp;gt; in the backtrace.&amp;#039;&amp;#039;&amp;#039; Almost always means missing &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; or missing &amp;lt;code&amp;gt;-fno-omit-frame-pointer&amp;lt;/code&amp;gt;. Without frame pointers, the unwinder on x86_64 falls back to imperfect heuristics.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The pipeline passes locally but ASan errors only appear in CI.&amp;#039;&amp;#039;&amp;#039; Check that your container image is using a recent enough compiler. GCC&amp;#039;s ASan got significantly better between 8.x and 11.x; UBSan added several checks in the same span. The Debian Bookworm &amp;lt;code&amp;gt;g++&amp;lt;/code&amp;gt; (12.x) is fine.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tests pass under the sanitizers locally, but a teammate&amp;#039;s machine shows different errors.&amp;#039;&amp;#039;&amp;#039; ASan and UBSan are deterministic for a given binary, but slight platform differences (libc version, glibc malloc settings) can occasionally surface bugs that are real but only fire on one machine. The CI container is the source of truth.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Valgrind reports complaints in the standard library.&amp;#039;&amp;#039;&amp;#039; Usually you can ignore these unless they reference your own code. Use &amp;lt;code&amp;gt;--suppressions=/usr/share/valgrind/default.supp&amp;lt;/code&amp;gt; (most distributions ship a default suppression file) to filter out the well-known libc and libstdc++ noise.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ASan says &amp;quot;AddressSanitizer: DEADLYSIGNAL&amp;quot; with no obvious cause.&amp;#039;&amp;#039;&amp;#039; Your program received a fatal signal (often SIGSEGV) inside ASan&amp;#039;s own instrumentation. This usually means very serious memory corruption or stack overflow. Use &amp;lt;code&amp;gt;ASAN_OPTIONS=abort_on_error=1&amp;lt;/code&amp;gt; to get a core dump and a clearer backtrace.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Some sanitizer findings disappear at &amp;lt;code&amp;gt;-O2&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;.&amp;#039;&amp;#039;&amp;#039; That is expected - the optimizer can eliminate the offending construct entirely. Keep your sanitizer build at &amp;lt;code&amp;gt;-O1&amp;lt;/code&amp;gt;: optimized enough to be realistic, unoptimized enough to keep reports trustworthy.&lt;br /&gt;
&lt;br /&gt;
== Looking ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week: &amp;#039;&amp;#039;&amp;#039;Documentation as Code&amp;#039;&amp;#039;&amp;#039;. You will add a Doxygen build to your CMake, publish the generated HTML docs as a GitLab Pages artifact, and turn your scattered code comments into navigable API documentation. Bring a piece of your capstone code that is poorly documented and you want to improve.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_9&amp;diff=8345</id>
		<title>SDPT Lab 9</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_9&amp;diff=8345"/>
		<updated>2026-05-11T13:34:01Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 9 Lab Activity: Dynamic Analysis with Sanitizers and Valgrind =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
&lt;br /&gt;
Extend your Oven Controller&amp;#039;s CI pipeline with a fourth quality gate: a &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage that builds the project under AddressSanitizer and UndefinedBehaviorSanitizer and runs your full test suite against the instrumented binary. By the end of this lab, your pipeline catches a fourth class of bug - runtime memory errors and undefined behavior - automatically on every push.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
You will add a new CMake build type called &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; that compiles with &amp;lt;code&amp;gt;-fsanitize=address,undefined&amp;lt;/code&amp;gt; alongside &amp;lt;code&amp;gt;-O1 -g -fno-omit-frame-pointer&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;-O1&amp;lt;/code&amp;gt; keeps the optimizer light enough that sanitizer reports stay readable; &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; embeds debug information so backtraces have line numbers; &amp;lt;code&amp;gt;-fno-omit-frame-pointer&amp;lt;/code&amp;gt; ensures those backtraces are actually complete on x86_64.&lt;br /&gt;
&lt;br /&gt;
The sanitizers report errors by printing to stderr and exiting with a nonzero status. This means your existing GoogleTest tests do not need any modification: if a test triggers a sanitizer error, the test binary aborts, ctest reports failure, the CI job fails, and the MR is blocked. The pipeline plumbing from Week 6 carries this work for you for free.&lt;br /&gt;
&lt;br /&gt;
In addition to the sanitizer build, you will run Valgrind manually once against the same codebase. The two tools are complementary: ASan is fast and runs in CI; Valgrind is slow but sometimes catches things ASan misses (notably uninitialized reads, which require MemorySanitizer to catch with sanitizers - and you saw in the lecture why MSan is impractical).&lt;br /&gt;
&lt;br /&gt;
You will also reuse &amp;lt;code&amp;gt;gcovr&amp;lt;/code&amp;gt; from Week 4. Dynamic analysis can only find bugs on code paths your tests actually execute, so coverage is part of the deliverable.&lt;br /&gt;
&lt;br /&gt;
The point of this lab is not to introduce new tools you have never seen - you have met all four (ASan/UBSan/Valgrind/gcovr) in lectures. The point is to wire them together into your existing pipeline and prove the wiring works by deliberately breaking things.&lt;br /&gt;
&lt;br /&gt;
Documentation pointers: &amp;lt;code&amp;gt;man valgrind&amp;lt;/code&amp;gt;, the AddressSanitizer wiki at https://github.com/google/sanitizers/wiki/AddressSanitizer, the UBSan documentation at https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html, and your existing gcovr docs.&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Work on a feature branch opened from a tracked Issue. Open a Merge Request when you are ready to integrate.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Extend the Docker build environment.&amp;#039;&amp;#039;&amp;#039; Update your &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; to install &amp;lt;code&amp;gt;valgrind&amp;lt;/code&amp;gt; alongside the tools already present. Rebuild and verify with &amp;lt;code&amp;gt;valgrind --version&amp;lt;/code&amp;gt;. The sanitizers themselves ship with the compiler, so no separate package is needed - but confirm by running &amp;lt;code&amp;gt;echo &amp;quot;int main(){}&amp;quot; | g++ -fsanitize=address -x c++ - -o /dev/null&amp;lt;/code&amp;gt; inside the container; if that succeeds, ASan is available.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add the Sanitize build type to CMake.&amp;#039;&amp;#039;&amp;#039; In your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;, add logic that, when &amp;lt;code&amp;gt;CMAKE_BUILD_TYPE&amp;lt;/code&amp;gt; equals &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt;, sets compile and link options for &amp;lt;code&amp;gt;-fsanitize=address,undefined&amp;lt;/code&amp;gt; plus &amp;lt;code&amp;gt;-O1 -g -fno-omit-frame-pointer&amp;lt;/code&amp;gt;. Make sure both compile &amp;#039;&amp;#039;and&amp;#039;&amp;#039; link options include the sanitizer flag - if you forget the link side, you will get cryptic linker errors about missing &amp;lt;code&amp;gt;__asan_*&amp;lt;/code&amp;gt; symbols. Test locally: &amp;lt;code&amp;gt;cmake -B build-san -DCMAKE_BUILD_TYPE=Sanitize&amp;lt;/code&amp;gt;, then build, then run a test binary directly to confirm it produces output that mentions ASan.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Run your existing tests under the sanitizers and clean up.&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;ctest --test-dir build-san --output-on-failure&amp;lt;/code&amp;gt;. If any tests fail due to sanitizer reports, fix the underlying bugs in the Oven Controller code (do &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; suppress them). Typical findings in EE-trained codebases: forgotten &amp;lt;code&amp;gt;delete[]&amp;lt;/code&amp;gt;, signed overflow in temperature math, reading from a member variable that was never initialized in a constructor. Each fix should be its own small commit with a message describing what the sanitizer reported.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add a sanitize stage to GitLab CI.&amp;#039;&amp;#039;&amp;#039; Edit &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to add a new &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage after &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;. The job should: configure a &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; build, compile it, and run &amp;lt;code&amp;gt;ctest&amp;lt;/code&amp;gt; against it. Use your existing Docker image. The job must fail the pipeline on any sanitizer error.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger ASan on purpose.&amp;#039;&amp;#039;&amp;#039; On your feature branch, introduce a deliberate &amp;#039;&amp;#039;&amp;#039;heap-buffer-overflow&amp;#039;&amp;#039;&amp;#039; bug somewhere in the production code. Push, watch the &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage fail, capture the ASan report (the job-log permalink in the MR description is sufficient), then revert. Your goal is to see the full ASan diagnostic - the line with the offending access, the line of the allocation, and the &amp;quot;stack-buffer-overflow&amp;quot; or &amp;quot;heap-buffer-overflow&amp;quot; classification.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger UBSan on purpose.&amp;#039;&amp;#039;&amp;#039; Repeat with a deliberate &amp;#039;&amp;#039;&amp;#039;signed integer overflow&amp;#039;&amp;#039;&amp;#039; or &amp;#039;&amp;#039;&amp;#039;null pointer dereference&amp;#039;&amp;#039;&amp;#039;. The UBSan report looks different from ASan&amp;#039;s - a one-line &amp;quot;runtime error&amp;quot; message at the trigger point. Capture, revert.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger LeakSanitizer on purpose.&amp;#039;&amp;#039;&amp;#039; Repeat with a deliberate memory leak (allocate something on the heap, do not free it). LeakSan reports at program exit, not at the leak site. Capture, revert.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Run Valgrind once, manually.&amp;#039;&amp;#039;&amp;#039; Build your project in a normal Debug configuration (no sanitizers - they conflict with Valgrind&amp;#039;s instrumentation). From inside your Docker container, run &amp;lt;code&amp;gt;valgrind --leak-check=full --show-leakkinds=all --track-origins=yes ./your_test_binary&amp;lt;/code&amp;gt;. Save the full output. If Valgrind reports any errors that ASan did not, fix them. Add a paragraph to your MR description noting which tool caught what, or that the two agreed completely.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Re-check coverage.&amp;#039;&amp;#039;&amp;#039; Recall from Week 4: &amp;lt;code&amp;gt;gcovr -r .. --html-details&amp;lt;/code&amp;gt; against a coverage-instrumented build. Generate a current coverage report. Compare against your Week 4 baseline. If coverage dropped, write enough additional tests to bring it back. Coverage gaps are places where sanitizer findings are silently impossible, so this is part of the dynamic-analysis story even if the tool is the same one you used in Week 4.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Document the cost.&amp;#039;&amp;#039;&amp;#039; Compare the wall-clock time of your full pipeline before and after this lab. The &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage adds work; document by how much in your MR description. As in Week 7, &amp;quot;the sanitize stage adds 6 minutes and we caught two real bugs&amp;quot; is a more honest finding than rounding to &amp;quot;negligible&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Review and merge.&amp;#039;&amp;#039;&amp;#039; Open the MR. The reviewer should check: the Sanitize build type works locally and in CI, that the three deliberate-bug pipeline runs are visible, that the Valgrind output is referenced in the MR, that coverage has not regressed.&lt;br /&gt;
&lt;br /&gt;
== Stretch tasks (optional, if you finish early) ==&lt;br /&gt;
&lt;br /&gt;
Pick at most one. None earn extra points; all teach you something useful.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Add a second sanitizer build.&amp;#039;&amp;#039;&amp;#039; Some teams maintain two CI jobs: one with ASan+UBSan, one with ThreadSanitizer. Add a TSan job that builds with &amp;lt;code&amp;gt;-fsanitize=thread&amp;lt;/code&amp;gt; and runs the tests. Even on single-threaded code this is harmless, and it sets you up for the day you add concurrency.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Valgrind in CI.&amp;#039;&amp;#039;&amp;#039; Add a manual-trigger CI job (using GitLab&amp;#039;s &amp;lt;code&amp;gt;when: manual&amp;lt;/code&amp;gt;) that runs Valgrind on your test binary. It is too slow to run on every push, but a one-click button for the weekly deep audit is valuable.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Coverage threshold gate.&amp;#039;&amp;#039;&amp;#039; Use &amp;lt;code&amp;gt;gcovr --fail-under-line N&amp;lt;/code&amp;gt; to fail the pipeline if line coverage drops below a threshold you choose (e.g. 80%). Now coverage is also an automatic quality gate, not just a number.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sanitizer-specific environment variables.&amp;#039;&amp;#039;&amp;#039; Read the docs for &amp;lt;code&amp;gt;ASAN_OPTIONS&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UBSAN_OPTIONS&amp;lt;/code&amp;gt;. Add &amp;lt;code&amp;gt;halt_on_error=1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;abort_on_error=1&amp;lt;/code&amp;gt; to your CI environment, which makes the first error a hard stop instead of letting the program limp on. Useful for getting clearer reports.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
For this lab to be marked complete, your &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch must contain:&lt;br /&gt;
&lt;br /&gt;
# A &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; that installs &amp;lt;code&amp;gt;valgrind&amp;lt;/code&amp;gt; in addition to the previous week&amp;#039;s tooling.&lt;br /&gt;
# A &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; with a working &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; build type.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage running after the &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
# A merged Merge Request whose linked Issue (or MR description) contains:&lt;br /&gt;
## References to &amp;#039;&amp;#039;&amp;#039;three&amp;#039;&amp;#039;&amp;#039; failed pipeline runs from Tasks 5, 6, and 7 (one each for ASan, UBSan, and LeakSan), with the relevant snippet of each sanitizer&amp;#039;s report quoted briefly.&lt;br /&gt;
## The Valgrind output from Task 8, or a permalink to it (a job artifact or a gist).&lt;br /&gt;
## A note comparing Valgrind&amp;#039;s findings with the sanitizers&amp;#039; findings (Task 8).&lt;br /&gt;
## The coverage comparison from Task 9 (before/after, plus what you did about it).&lt;br /&gt;
## The pipeline cost comparison from Task 10.&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Linker errors mentioning &amp;lt;code&amp;gt;__asan_*&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;__ubsan_*&amp;lt;/code&amp;gt; symbols.&amp;#039;&amp;#039;&amp;#039; You set the sanitizer flag for compilation but forgot to also pass it at the link step. In CMake, both &amp;lt;code&amp;gt;add_compile_options&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;add_link_options&amp;lt;/code&amp;gt; need &amp;lt;code&amp;gt;-fsanitize=...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sanitizers and Valgrind conflict.&amp;#039;&amp;#039;&amp;#039; You cannot run a sanitizer-built binary under Valgrind. They both rely on intercepting memory accesses and the interception clashes. Build a separate Debug binary (no sanitizers) when you want to run Valgrind.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ASan reports look truncated or have &amp;lt;code&amp;gt;??&amp;lt;/code&amp;gt; in the backtrace.&amp;#039;&amp;#039;&amp;#039; Almost always means missing &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; or missing &amp;lt;code&amp;gt;-fno-omit-frame-pointer&amp;lt;/code&amp;gt;. Without frame pointers, the unwinder on x86_64 falls back to imperfect heuristics.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The pipeline passes locally but ASan errors only appear in CI.&amp;#039;&amp;#039;&amp;#039; Check that your container image is using a recent enough compiler. GCC&amp;#039;s ASan got significantly better between 8.x and 11.x; UBSan added several checks in the same span. The Debian Bookworm &amp;lt;code&amp;gt;g++&amp;lt;/code&amp;gt; (12.x) is fine.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tests pass under the sanitizers locally, but a teammate&amp;#039;s machine shows different errors.&amp;#039;&amp;#039;&amp;#039; ASan and UBSan are deterministic for a given binary, but slight platform differences (libc version, glibc malloc settings) can occasionally surface bugs that are real but only fire on one machine. The CI container is the source of truth.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Valgrind reports complaints in the standard library.&amp;#039;&amp;#039;&amp;#039; Usually you can ignore these unless they reference your own code. Use &amp;lt;code&amp;gt;--suppressions=/usr/share/valgrind/default.supp&amp;lt;/code&amp;gt; (most distributions ship a default suppression file) to filter out the well-known libc and libstdc++ noise.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ASan says &amp;quot;AddressSanitizer: DEADLYSIGNAL&amp;quot; with no obvious cause.&amp;#039;&amp;#039;&amp;#039; Your program received a fatal signal (often SIGSEGV) inside ASan&amp;#039;s own instrumentation. This usually means very serious memory corruption or stack overflow. Use &amp;lt;code&amp;gt;ASAN_OPTIONS=abort_on_error=1&amp;lt;/code&amp;gt; to get a core dump and a clearer backtrace.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Some sanitizer findings disappear at &amp;lt;code&amp;gt;-O2&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;.&amp;#039;&amp;#039;&amp;#039; That is expected - the optimizer can eliminate the offending construct entirely. Keep your sanitizer build at &amp;lt;code&amp;gt;-O1&amp;lt;/code&amp;gt;: optimized enough to be realistic, unoptimized enough to keep reports trustworthy.&lt;br /&gt;
&lt;br /&gt;
== Looking ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week: &amp;#039;&amp;#039;&amp;#039;Documentation as Code&amp;#039;&amp;#039;&amp;#039;. You will add a Doxygen build to your CMake, publish the generated HTML docs as a GitLab Pages artifact, and turn your scattered code comments into navigable API documentation. Bring a piece of your capstone code that is poorly documented and you want to improve.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_9&amp;diff=8344</id>
		<title>SDPT Lab 9</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_9&amp;diff=8344"/>
		<updated>2026-05-11T13:33:13Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: = Week 9 Lab Activity: Dynamic Analysis with Sanitizers and Valgrind =  == Objective ==  Extend your Oven Controller&amp;#039;s CI pipeline with a fourth quality gate: a &amp;lt;code&amp;gt;sanitize&amp;lt;/cod...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 9 Lab Activity: Dynamic Analysis with Sanitizers and Valgrind =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
&lt;br /&gt;
Extend your Oven Controller&amp;#039;s CI pipeline with a fourth quality gate: a &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage that builds the project under AddressSanitizer and UndefinedBehaviorSanitizer and runs your full test suite against the instrumented binary. By the end of this lab, your pipeline catches a fourth class of bug --- runtime memory errors and undefined behavior --- automatically on every push.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
You will add a new CMake build type called &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; that compiles with &amp;lt;code&amp;gt;-fsanitize=address,undefined&amp;lt;/code&amp;gt; alongside &amp;lt;code&amp;gt;-O1 -g -fno-omit-frame-pointer&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;-O1&amp;lt;/code&amp;gt; keeps the optimizer light enough that sanitizer reports stay readable; &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; embeds debug information so backtraces have line numbers; &amp;lt;code&amp;gt;-fno-omit-frame-pointer&amp;lt;/code&amp;gt; ensures those backtraces are actually complete on x86_64.&lt;br /&gt;
&lt;br /&gt;
The sanitizers report errors by printing to stderr and exiting with a nonzero status. This means your existing GoogleTest tests do not need any modification: if a test triggers a sanitizer error, the test binary aborts, ctest reports failure, the CI job fails, and the MR is blocked. The pipeline plumbing from Week 6 carries this work for you for free.&lt;br /&gt;
&lt;br /&gt;
In addition to the sanitizer build, you will run Valgrind manually once against the same codebase. The two tools are complementary: ASan is fast and runs in CI; Valgrind is slow but sometimes catches things ASan misses (notably uninitialized reads, which require MemorySanitizer to catch with sanitizers --- and you saw in the lecture why MSan is impractical).&lt;br /&gt;
&lt;br /&gt;
You will also reuse &amp;lt;code&amp;gt;gcovr&amp;lt;/code&amp;gt; from Week 4. Dynamic analysis can only find bugs on code paths your tests actually execute, so coverage is part of the deliverable.&lt;br /&gt;
&lt;br /&gt;
The point of this lab is not to introduce new tools you have never seen --- you have met all four (ASan/UBSan/Valgrind/gcovr) in lectures. The point is to wire them together into your existing pipeline and prove the wiring works by deliberately breaking things.&lt;br /&gt;
&lt;br /&gt;
Documentation pointers: &amp;lt;code&amp;gt;man valgrind&amp;lt;/code&amp;gt;, the AddressSanitizer wiki at https://github.com/google/sanitizers/wiki/AddressSanitizer, the UBSan documentation at https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html, and your existing gcovr docs.&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Work on a feature branch opened from a tracked Issue. Open a Merge Request when you are ready to integrate.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Extend the Docker build environment.&amp;#039;&amp;#039;&amp;#039; Update your &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; to install &amp;lt;code&amp;gt;valgrind&amp;lt;/code&amp;gt; alongside the tools already present. Rebuild and verify with &amp;lt;code&amp;gt;valgrind --version&amp;lt;/code&amp;gt;. The sanitizers themselves ship with the compiler, so no separate package is needed --- but confirm by running &amp;lt;code&amp;gt;echo &amp;quot;int main(){}&amp;quot; | g++ -fsanitize=address -x c++ - -o /dev/null&amp;lt;/code&amp;gt; inside the container; if that succeeds, ASan is available.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add the Sanitize build type to CMake.&amp;#039;&amp;#039;&amp;#039; In your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;, add logic that, when &amp;lt;code&amp;gt;CMAKE_BUILD_TYPE&amp;lt;/code&amp;gt; equals &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt;, sets compile and link options for &amp;lt;code&amp;gt;-fsanitize=address,undefined&amp;lt;/code&amp;gt; plus &amp;lt;code&amp;gt;-O1 -g -fno-omit-frame-pointer&amp;lt;/code&amp;gt;. Make sure both compile &amp;#039;&amp;#039;and&amp;#039;&amp;#039; link options include the sanitizer flag --- if you forget the link side, you will get cryptic linker errors about missing &amp;lt;code&amp;gt;__asan_*&amp;lt;/code&amp;gt; symbols. Test locally: &amp;lt;code&amp;gt;cmake -B build-san -DCMAKE_BUILD_TYPE=Sanitize&amp;lt;/code&amp;gt;, then build, then run a test binary directly to confirm it produces output that mentions ASan.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Run your existing tests under the sanitizers and clean up.&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;ctest --test-dir build-san --output-on-failure&amp;lt;/code&amp;gt;. If any tests fail due to sanitizer reports, fix the underlying bugs in the Oven Controller code (do &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; suppress them). Typical findings in EE-trained codebases: forgotten &amp;lt;code&amp;gt;delete[]&amp;lt;/code&amp;gt;, signed overflow in temperature math, reading from a member variable that was never initialized in a constructor. Each fix should be its own small commit with a message describing what the sanitizer reported.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add a sanitize stage to GitLab CI.&amp;#039;&amp;#039;&amp;#039; Edit &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to add a new &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage after &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;. The job should: configure a &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; build, compile it, and run &amp;lt;code&amp;gt;ctest&amp;lt;/code&amp;gt; against it. Use your existing Docker image. The job must fail the pipeline on any sanitizer error.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger ASan on purpose.&amp;#039;&amp;#039;&amp;#039; On your feature branch, introduce a deliberate &amp;#039;&amp;#039;&amp;#039;heap-buffer-overflow&amp;#039;&amp;#039;&amp;#039; bug somewhere in the production code. Push, watch the &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage fail, capture the ASan report (the job-log permalink in the MR description is sufficient), then revert. Your goal is to see the full ASan diagnostic --- the line with the offending access, the line of the allocation, and the &amp;quot;stack-buffer-overflow&amp;quot; or &amp;quot;heap-buffer-overflow&amp;quot; classification.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger UBSan on purpose.&amp;#039;&amp;#039;&amp;#039; Repeat with a deliberate &amp;#039;&amp;#039;&amp;#039;signed integer overflow&amp;#039;&amp;#039;&amp;#039; or &amp;#039;&amp;#039;&amp;#039;null pointer dereference&amp;#039;&amp;#039;&amp;#039;. The UBSan report looks different from ASan&amp;#039;s --- a one-line &amp;quot;runtime error&amp;quot; message at the trigger point. Capture, revert.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Trigger LeakSanitizer on purpose.&amp;#039;&amp;#039;&amp;#039; Repeat with a deliberate memory leak (allocate something on the heap, do not free it). LeakSan reports at program exit, not at the leak site. Capture, revert.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Run Valgrind once, manually.&amp;#039;&amp;#039;&amp;#039; Build your project in a normal Debug configuration (no sanitizers --- they conflict with Valgrind&amp;#039;s instrumentation). From inside your Docker container, run &amp;lt;code&amp;gt;valgrind --leak-check=full --show-leakkinds=all --track-origins=yes ./your_test_binary&amp;lt;/code&amp;gt;. Save the full output. If Valgrind reports any errors that ASan did not, fix them. Add a paragraph to your MR description noting which tool caught what, or that the two agreed completely.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Re-check coverage.&amp;#039;&amp;#039;&amp;#039; Recall from Week 4: &amp;lt;code&amp;gt;gcovr -r .. --html-details&amp;lt;/code&amp;gt; against a coverage-instrumented build. Generate a current coverage report. Compare against your Week 4 baseline. If coverage dropped, write enough additional tests to bring it back. Coverage gaps are places where sanitizer findings are silently impossible, so this is part of the dynamic-analysis story even if the tool is the same one you used in Week 4.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Document the cost.&amp;#039;&amp;#039;&amp;#039; Compare the wall-clock time of your full pipeline before and after this lab. The &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage adds work; document by how much in your MR description. As in Week 7, &amp;quot;the sanitize stage adds 6 minutes and we caught two real bugs&amp;quot; is a more honest finding than rounding to &amp;quot;negligible&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Review and merge.&amp;#039;&amp;#039;&amp;#039; Open the MR. The reviewer should check: the Sanitize build type works locally and in CI, that the three deliberate-bug pipeline runs are visible, that the Valgrind output is referenced in the MR, that coverage has not regressed.&lt;br /&gt;
&lt;br /&gt;
== Stretch tasks (optional, if you finish early) ==&lt;br /&gt;
&lt;br /&gt;
Pick at most one. None earn extra points; all teach you something useful.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Add a second sanitizer build.&amp;#039;&amp;#039;&amp;#039; Some teams maintain two CI jobs: one with ASan+UBSan, one with ThreadSanitizer. Add a TSan job that builds with &amp;lt;code&amp;gt;-fsanitize=thread&amp;lt;/code&amp;gt; and runs the tests. Even on single-threaded code this is harmless, and it sets you up for the day you add concurrency.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Valgrind in CI.&amp;#039;&amp;#039;&amp;#039; Add a manual-trigger CI job (using GitLab&amp;#039;s &amp;lt;code&amp;gt;when: manual&amp;lt;/code&amp;gt;) that runs Valgrind on your test binary. It is too slow to run on every push, but a one-click button for the weekly deep audit is valuable.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Coverage threshold gate.&amp;#039;&amp;#039;&amp;#039; Use &amp;lt;code&amp;gt;gcovr --fail-under-line N&amp;lt;/code&amp;gt; to fail the pipeline if line coverage drops below a threshold you choose (e.g. 80%). Now coverage is also an automatic quality gate, not just a number.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sanitizer-specific environment variables.&amp;#039;&amp;#039;&amp;#039; Read the docs for &amp;lt;code&amp;gt;ASAN_OPTIONS&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UBSAN_OPTIONS&amp;lt;/code&amp;gt;. Add &amp;lt;code&amp;gt;halt_on_error=1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;abort_on_error=1&amp;lt;/code&amp;gt; to your CI environment, which makes the first error a hard stop instead of letting the program limp on. Useful for getting clearer reports.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
For this lab to be marked complete, your &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch must contain:&lt;br /&gt;
&lt;br /&gt;
# A &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; that installs &amp;lt;code&amp;gt;valgrind&amp;lt;/code&amp;gt; in addition to the previous week&amp;#039;s tooling.&lt;br /&gt;
# A &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; with a working &amp;lt;code&amp;gt;Sanitize&amp;lt;/code&amp;gt; build type.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;sanitize&amp;lt;/code&amp;gt; stage running after the &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
# A merged Merge Request whose linked Issue (or MR description) contains:&lt;br /&gt;
## References to &amp;#039;&amp;#039;&amp;#039;three&amp;#039;&amp;#039;&amp;#039; failed pipeline runs from Tasks 5, 6, and 7 (one each for ASan, UBSan, and LeakSan), with the relevant snippet of each sanitizer&amp;#039;s report quoted briefly.&lt;br /&gt;
## The Valgrind output from Task 8, or a permalink to it (a job artifact or a gist).&lt;br /&gt;
## A note comparing Valgrind&amp;#039;s findings with the sanitizers&amp;#039; findings (Task 8).&lt;br /&gt;
## The coverage comparison from Task 9 (before/after, plus what you did about it).&lt;br /&gt;
## The pipeline cost comparison from Task 10.&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Linker errors mentioning &amp;lt;code&amp;gt;__asan_*&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;__ubsan_*&amp;lt;/code&amp;gt; symbols.&amp;#039;&amp;#039;&amp;#039; You set the sanitizer flag for compilation but forgot to also pass it at the link step. In CMake, both &amp;lt;code&amp;gt;add_compile_options&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;add_link_options&amp;lt;/code&amp;gt; need &amp;lt;code&amp;gt;-fsanitize=...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sanitizers and Valgrind conflict.&amp;#039;&amp;#039;&amp;#039; You cannot run a sanitizer-built binary under Valgrind. They both rely on intercepting memory accesses and the interception clashes. Build a separate Debug binary (no sanitizers) when you want to run Valgrind.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ASan reports look truncated or have &amp;lt;code&amp;gt;??&amp;lt;/code&amp;gt; in the backtrace.&amp;#039;&amp;#039;&amp;#039; Almost always means missing &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; or missing &amp;lt;code&amp;gt;-fno-omit-frame-pointer&amp;lt;/code&amp;gt;. Without frame pointers, the unwinder on x86_64 falls back to imperfect heuristics.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The pipeline passes locally but ASan errors only appear in CI.&amp;#039;&amp;#039;&amp;#039; Check that your container image is using a recent enough compiler. GCC&amp;#039;s ASan got significantly better between 8.x and 11.x; UBSan added several checks in the same span. The Debian Bookworm &amp;lt;code&amp;gt;g++&amp;lt;/code&amp;gt; (12.x) is fine.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tests pass under the sanitizers locally, but a teammate&amp;#039;s machine shows different errors.&amp;#039;&amp;#039;&amp;#039; ASan and UBSan are deterministic for a given binary, but slight platform differences (libc version, glibc malloc settings) can occasionally surface bugs that are real but only fire on one machine. The CI container is the source of truth.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Valgrind reports complaints in the standard library.&amp;#039;&amp;#039;&amp;#039; Usually you can ignore these unless they reference your own code. Use &amp;lt;code&amp;gt;--suppressions=/usr/share/valgrind/default.supp&amp;lt;/code&amp;gt; (most distributions ship a default suppression file) to filter out the well-known libc and libstdc++ noise.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ASan says &amp;quot;AddressSanitizer: DEADLYSIGNAL&amp;quot; with no obvious cause.&amp;#039;&amp;#039;&amp;#039; Your program received a fatal signal (often SIGSEGV) inside ASan&amp;#039;s own instrumentation. This usually means very serious memory corruption or stack overflow. Use &amp;lt;code&amp;gt;ASAN_OPTIONS=abort_on_error=1&amp;lt;/code&amp;gt; to get a core dump and a clearer backtrace.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Some sanitizer findings disappear at &amp;lt;code&amp;gt;-O2&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;.&amp;#039;&amp;#039;&amp;#039; That is expected --- the optimizer can eliminate the offending construct entirely. Keep your sanitizer build at &amp;lt;code&amp;gt;-O1&amp;lt;/code&amp;gt;: optimized enough to be realistic, unoptimized enough to keep reports trustworthy.&lt;br /&gt;
&lt;br /&gt;
== Looking ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week: &amp;#039;&amp;#039;&amp;#039;Documentation as Code&amp;#039;&amp;#039;&amp;#039;. You will add a Doxygen build to your CMake, publish the generated HTML docs as a GitLab Pages artifact, and turn your scattered code comments into navigable API documentation. Bring a piece of your capstone code that is poorly documented and you want to improve.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8343</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8343"/>
		<updated>2026-05-11T13:33:07Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;br /&gt;
* [[SDPT Lab 2]]&lt;br /&gt;
* [[SDPT Lab 3]]&lt;br /&gt;
* [[SDPT Lab 4]]&lt;br /&gt;
* [[SDPT Lab 5]]&lt;br /&gt;
* [[SDPT Lab 6]]&lt;br /&gt;
* [[SDPT Lab 7]]&lt;br /&gt;
* [[SDPT Lab 8]]&lt;br /&gt;
* [[SDPT Lab 9]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_8&amp;diff=8342</id>
		<title>SDPT Lab 8</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_8&amp;diff=8342"/>
		<updated>2026-05-04T13:34:48Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: = Week 8 Lab Activity: Networking, Security, and VPNs =  == Objective ==  Bring up two VMs that you fully control --- one acting as the server, one as an ARM-based &amp;#039;&amp;#039;edge device&amp;#039;&amp;#039;...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 8 Lab Activity: Networking, Security, and VPNs =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
&lt;br /&gt;
Bring up two VMs that you fully control --- one acting as the server, one as an ARM-based &amp;#039;&amp;#039;edge device&amp;#039;&amp;#039; --- and use them to practice the techniques from this week&amp;#039;s lecture: a raw TCP echo, an HTTP/REST exchange, a TLS-protected version of the same, and a three-peer WireGuard mesh that stitches your laptop and both VMs into one private encrypted overlay network.&lt;br /&gt;
&lt;br /&gt;
This lab is allowed to run longer than your usual 1h50min. Plan for roughly 2h30min if you have not used QEMU before.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
=== Why two VMs ===&lt;br /&gt;
&lt;br /&gt;
Your capstone has two physical machines (a Pi and a server VM). For this lab you do not have a Pi, so you will emulate one with QEMU running an ARM64 Debian image. This has two pedagogical benefits: you practice exactly the cross-architecture work that production embedded developers do, and you get a self-contained environment that does not depend on lab hardware or shared infrastructure.&lt;br /&gt;
&lt;br /&gt;
=== Choosing your virtualization stack ===&lt;br /&gt;
&lt;br /&gt;
You have several options for running VMs on your laptop. Each has tradeoffs that matter for this lab.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;VirtualBox + QEMU mixed.&amp;#039;&amp;#039;&amp;#039; The most common student instinct is to use VirtualBox (familiar GUI) for the x86 VM and QEMU for the ARM VM. This is the option to &amp;#039;&amp;#039;avoid&amp;#039;&amp;#039;. On Windows, VirtualBox 7.x technically coexists with QEMU&amp;#039;s WHPX accelerator, but the two compete for the same hypervisor primitives and you will see strange failures (slow boots, network glitches, occasional VM crashes) that are extremely hard to diagnose mid-lab.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;KVM (Linux native).&amp;#039;&amp;#039;&amp;#039; If your laptop runs Linux, KVM is built into the kernel and gives you near-native VM speed for x86 guests. ARM guests still run under TCG (software emulation) since you are emulating a different architecture. This is the cleanest option if it is available to you.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;QEMU on Windows with WHPX.&amp;#039;&amp;#039;&amp;#039; QEMU runs natively on Windows. For x86 guests it can use Microsoft&amp;#039;s WHPX accelerator, giving acceptable performance. &amp;#039;&amp;#039;But&amp;#039;&amp;#039; WHPX only accelerates same-architecture virtualization, so your ARM VM will boot in software emulation: functional, but slow (5--10 minutes to first login).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;WSL2 on Windows.&amp;#039;&amp;#039;&amp;#039; Run everything inside WSL2 and treat your machine as a Linux host. This works well, requires a one-time WSL2 setup, and lets you follow the Linux instructions verbatim. Best Windows option if you are willing to set up WSL2.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;QEMU on macOS with HVF.&amp;#039;&amp;#039;&amp;#039; QEMU on macOS can use the Hypervisor.framework accelerator (`-accel hvf`) for x86 guests. ARM guests use TCG. Apple Silicon Macs are an interesting case: the ARM VM is actually &amp;#039;&amp;#039;faster&amp;#039;&amp;#039; than the x86 VM, because ARM is the native architecture. Adjust the architecture flags accordingly.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Recommendation for this lab: QEMU for both VMs, on whatever host OS you have.&amp;#039;&amp;#039;&amp;#039; One tool, one set of quirks, one mental model. The setup tutorial below uses QEMU exclusively.&lt;br /&gt;
&lt;br /&gt;
=== Networking the two VMs ===&lt;br /&gt;
&lt;br /&gt;
QEMU offers two relevant networking modes. &amp;#039;&amp;#039;&amp;#039;User-mode networking&amp;#039;&amp;#039;&amp;#039; (`-net user` or `-netdev user`) is the default: simple, requires no permissions, but the VMs cannot directly address each other --- they each see a private NAT&amp;#039;d network. Useful for outbound-only traffic (apt-get, ssh &amp;#039;&amp;#039;into&amp;#039;&amp;#039; the VM via port-forwarding), useless for &amp;quot;VM A talks to VM B&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;TAP-based bridged networking&amp;#039;&amp;#039;&amp;#039; (`-netdev tap`) gives each VM a real-looking interface on a software bridge on the host. The VMs can address each other directly using their bridge IPs. This is what we need. On Linux it requires a `bridge-utils` setup (15 minutes once); on Windows it requires installing the OpenVPN TAP driver and is fiddlier; on macOS it is well-supported.&lt;br /&gt;
&lt;br /&gt;
For the lab, we will use a third hybrid option that works the same on all platforms: &amp;#039;&amp;#039;&amp;#039;each VM uses user-mode networking to reach the internet, plus a second `socket` interface that connects the two VMs directly&amp;#039;&amp;#039;&amp;#039;. This is QEMU&amp;#039;s `-netdev socket` feature: one VM listens on a TCP port, the other connects to it, and to both guests it looks like a normal network interface. No bridge, no admin permissions, no platform-specific drivers.&lt;br /&gt;
&lt;br /&gt;
=== The cpp-httplib library ===&lt;br /&gt;
&lt;br /&gt;
Single-header HTTP server and client at https://github.com/yhirose/cpp-httplib. Drop `httplib.h` next to your code, `#include` it, you have HTTP. With `-DCPPHTTPLIB_OPENSSL_SUPPORT` and OpenSSL installed, the same library gives you HTTPS via `httplib::SSLServer` and `httplib::SSLClient`. For JSON, use https://github.com/nlohmann/json (also single-header).&lt;br /&gt;
&lt;br /&gt;
=== WireGuard ===&lt;br /&gt;
&lt;br /&gt;
WireGuard is in the Linux kernel since 5.6. Configuration is one short text file per peer. Each peer has a public/private keypair generated with `wg genkey | tee privatekey | wg pubkey &amp;gt; publickey`. Each peer&amp;#039;s config lists the other peers&amp;#039; public keys and which IPs to expect from each. Useful references: `man wg`, `man wg-quick`, https://www.wireguard.com/quickstart/.&lt;br /&gt;
&lt;br /&gt;
=== Wireshark ===&lt;br /&gt;
&lt;br /&gt;
The standard packet inspection tool. Useful filters for this lab: `tcp.port == 9000`, `http`, `tls`, `udp.port == 51820`. &amp;#039;&amp;#039;Tip:&amp;#039;&amp;#039; to capture traffic between two QEMU VMs that talk over a `socket` interface, capture on the loopback interface of your host (since QEMU&amp;#039;s socket netdev tunnels through host TCP).&lt;br /&gt;
&lt;br /&gt;
== Setup tutorial: bringing up the two VMs ==&lt;br /&gt;
&lt;br /&gt;
Allocate roughly 20--30 minutes for this section. Read through it once before typing.&lt;br /&gt;
&lt;br /&gt;
=== Step S1: install QEMU ===&lt;br /&gt;
&lt;br /&gt;
* Linux (Debian/Ubuntu): `sudo apt install qemu-system-x86 qemu-system-arm qemu-utils ovmf qemu-efi-aarch64`&lt;br /&gt;
* Linux (Fedora/RHEL): `sudo dnf install qemu-system-x86 qemu-system-aarch64 qemu-img edk2-ovmf edk2-aarch64`&lt;br /&gt;
* macOS (Homebrew): `brew install qemu`&lt;br /&gt;
* Windows: download the installer from https://www.qemu.org/download/#windows and add the install directory to your PATH. Verify with `qemu-system-x86_64 --version` in a fresh terminal.&lt;br /&gt;
&lt;br /&gt;
You also need OpenSSL (for the TLS exercise) and Wireshark on your host. Install via your package manager or https://www.wireshark.org/.&lt;br /&gt;
&lt;br /&gt;
=== Step S2: download the two cloud images ===&lt;br /&gt;
&lt;br /&gt;
We use Debian&amp;#039;s &amp;#039;&amp;#039;generic cloud images&amp;#039;&amp;#039; because they are designed for virtualization and boot quickly. Both are ~600 MB.&lt;br /&gt;
&lt;br /&gt;
* x86 server image: https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2&lt;br /&gt;
* ARM edge image: https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-arm64.qcow2&lt;br /&gt;
&lt;br /&gt;
Save both to a working directory, e.g. `~/lab8/`.&lt;br /&gt;
&lt;br /&gt;
=== Step S3: create a cloud-init seed image (one for each VM) ===&lt;br /&gt;
&lt;br /&gt;
The cloud images expect a tiny &amp;quot;seed&amp;quot; disk on first boot that tells them the hostname, the user account, and an SSH key. Create two text files:&lt;br /&gt;
&lt;br /&gt;
`user-data-server`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#cloud-config&lt;br /&gt;
hostname: lab8-server&lt;br /&gt;
users:&lt;br /&gt;
  - name: lab&lt;br /&gt;
    sudo: ALL=(ALL) NOPASSWD:ALL&lt;br /&gt;
    shell: /bin/bash&lt;br /&gt;
    lock_passwd: false&lt;br /&gt;
    plain_text_passwd: lab&lt;br /&gt;
    ssh_authorized_keys:&lt;br /&gt;
      - ssh-ed25519 AAAA... your-public-key-here&lt;br /&gt;
ssh_pwauth: true&lt;br /&gt;
chpasswd:&lt;br /&gt;
  expire: false&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
`user-data-edge` is identical except `hostname: lab8-edge`.&lt;br /&gt;
&lt;br /&gt;
Also create a one-line `meta-data` file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
instance-id: iid-local-01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Build the seed images with `cloud-localds` (Linux, comes with `cloud-image-utils`) or with `genisoimage`/`mkisofs`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cloud-localds seed-server.iso user-data-server meta-data&lt;br /&gt;
cloud-localds seed-edge.iso user-data-edge meta-data&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you do not have `cloud-localds`, the equivalent `genisoimage` invocation is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
genisoimage -output seed-server.iso -volid cidata -joliet -rock \&lt;br /&gt;
            user-data-server meta-data&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step S4: resize the disk images ===&lt;br /&gt;
&lt;br /&gt;
Default cloud images are tiny (~2 GB) and will fill up fast. Grow them to 8 GB each:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
qemu-img resize debian-12-genericcloud-amd64.qcow2 8G&lt;br /&gt;
qemu-img resize debian-12-genericcloud-arm64.qcow2 8G&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step S5: boot the x86 server VM ===&lt;br /&gt;
&lt;br /&gt;
Open a terminal and start the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
qemu-system-x86_64 \&lt;br /&gt;
  -name lab8-server \&lt;br /&gt;
  -machine q35 -accel kvm -accel whpx -accel hvf -accel tcg \&lt;br /&gt;
  -cpu max -m 1024 -smp 2 \&lt;br /&gt;
  -drive file=debian-12-genericcloud-amd64.qcow2,if=virtio \&lt;br /&gt;
  -drive file=seed-server.iso,if=virtio,format=raw \&lt;br /&gt;
  -netdev user,id=net0,hostfwd=tcp::2222-:22 \&lt;br /&gt;
  -device virtio-net-pci,netdev=net0 \&lt;br /&gt;
  -netdev socket,id=link,listen=:10000 \&lt;br /&gt;
  -device virtio-net-pci,netdev=link,mac=52:54:00:12:34:56 \&lt;br /&gt;
  -nographic&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes on this command line:&lt;br /&gt;
&lt;br /&gt;
* The `-accel kvm -accel whpx -accel hvf -accel tcg` chain tells QEMU to try the fastest accelerator available on whatever host OS you are running, falling back to TCG. You only get one of them; QEMU picks whichever works.&lt;br /&gt;
* The first `-netdev user` is for outbound traffic (apt, etc.) and forwards host port 2222 to the guest&amp;#039;s SSH.&lt;br /&gt;
* The second `-netdev socket,listen=:10000` is the inter-VM link --- this VM listens for the other VM to connect.&lt;br /&gt;
* `-nographic` disables the QEMU window and uses your terminal as the console. To exit QEMU: `Ctrl-A` then `X`.&lt;br /&gt;
&lt;br /&gt;
First boot takes 30--90 seconds. Wait for the login prompt and log in with user `lab`, password `lab`.&lt;br /&gt;
&lt;br /&gt;
In a second terminal, you can also SSH in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh -p 2222 lab@localhost&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step S6: boot the ARM edge VM ===&lt;br /&gt;
&lt;br /&gt;
In another terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
qemu-system-aarch64 \&lt;br /&gt;
  -name lab8-edge \&lt;br /&gt;
  -machine virt -cpu max -m 1024 -smp 2 \&lt;br /&gt;
  -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \&lt;br /&gt;
  -drive file=debian-12-genericcloud-arm64.qcow2,if=virtio \&lt;br /&gt;
  -drive file=seed-edge.iso,if=virtio,format=raw \&lt;br /&gt;
  -netdev user,id=net0,hostfwd=tcp::2223-:22 \&lt;br /&gt;
  -device virtio-net-pci,netdev=net0 \&lt;br /&gt;
  -netdev socket,id=link,connect=:10000 \&lt;br /&gt;
  -device virtio-net-pci,netdev=link,mac=52:54:00:12:34:57 \&lt;br /&gt;
  -nographic&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* `-machine virt` is QEMU&amp;#039;s generic ARM platform.&lt;br /&gt;
* `-bios` points to the UEFI firmware. The path varies by distro: on Fedora/RHEL it is `/usr/share/edk2/aarch64/QEMU_EFI.fd`; on macOS Homebrew it is `$(brew --prefix qemu)/share/qemu/edk2-aarch64-code.fd`; on Windows it ships in the QEMU install directory.&lt;br /&gt;
* The second `-netdev socket,connect=:10000` connects &amp;#039;&amp;#039;into&amp;#039;&amp;#039; the server VM&amp;#039;s listening socket. Start the server first, then start the edge.&lt;br /&gt;
* SSH in via `ssh -p 2223 lab@localhost`.&lt;br /&gt;
&lt;br /&gt;
ARM-on-x86 emulation is slow. Boot may take 5--10 minutes on first run. Be patient. On Apple Silicon hosts, ARM is native and boot is fast.&lt;br /&gt;
&lt;br /&gt;
=== Step S7: configure the inter-VM link ===&lt;br /&gt;
&lt;br /&gt;
The `socket` netdev gives each VM a second NIC, but the kernel does not auto-configure it. Inside &amp;#039;&amp;#039;each&amp;#039;&amp;#039; VM, find the second interface (probably `enp0s3` or `ens4`) and assign it a static IP on a private subnet:&lt;br /&gt;
&lt;br /&gt;
On the server VM:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ip link set ens4 up&lt;br /&gt;
sudo ip addr add 172.30.0.1/24 dev ens4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the edge VM:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ip link set ens4 up&lt;br /&gt;
sudo ip addr add 172.30.0.2/24 dev ens4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Substitute the actual interface name. `ip a` shows it.)&lt;br /&gt;
&lt;br /&gt;
Verify with `ping 172.30.0.2` from the server. If you see replies, the inter-VM link is up. If not, double-check that you started the server before the edge, and that both `socket` netdevs use the same port number.&lt;br /&gt;
&lt;br /&gt;
=== Step S8: install lab dependencies on both VMs ===&lt;br /&gt;
&lt;br /&gt;
Run on each VM:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt install -y build-essential cmake git \&lt;br /&gt;
                    libssl-dev nlohmann-json3-dev \&lt;br /&gt;
                    wireguard-tools tcpdump curl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For cpp-httplib, just download the single header into your working directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir -p ~/lab8 &amp;amp;&amp;amp; cd ~/lab8&lt;br /&gt;
wget https://raw.githubusercontent.com/yhirose/cpp-httplib/master/httplib.h&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You are now ready for the lab proper.&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Work in your `~/lab8` directory. Keep all the small programs you write --- you will submit them.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;TCP echo, raw sockets.&amp;#039;&amp;#039;&amp;#039; Write two C++ programs: a server that listens on TCP port 9000 and echoes back whatever it receives, and a client that connects, sends a short message read from `argv[1]`, prints the reply, and disconnects. Use POSIX sockets directly (`socket`, `bind`, `listen`, `accept`, `read`, `write`). Run the server on the server VM (binding to `172.30.0.1`); run the client from the edge VM, sending to `172.30.0.1:9000`. Verify the round trip works. Skim the data with `sudo tcpdump -i ens4 -A port 9000` on either VM during the exchange.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;HTTP/REST with cpp-httplib.&amp;#039;&amp;#039;&amp;#039; Replace your TCP echo with an HTTP equivalent. The server exposes one POST endpoint, `/access`, which expects a JSON body of the form `{&amp;quot;card_id&amp;quot;: &amp;quot;...&amp;quot;}` and replies with `{&amp;quot;granted&amp;quot;: true}` if the card ID is in a hardcoded allow-list of your choice (at least three IDs), otherwise `{&amp;quot;granted&amp;quot;: false}`. The client constructs the JSON, POSTs it, parses the reply, and prints `GRANTED` or `DENIED`. Use `nlohmann/json` for both encoding and decoding. Test from the command line first using `curl` against your server, before moving to the C++ client.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Inspect the wire.&amp;#039;&amp;#039;&amp;#039; Open Wireshark on the host, capturing on the loopback interface (since the QEMU socket link tunnels through host loopback). Trigger an HTTP request from your client. Find the request and the response in the capture. Confirm that you can read the card ID, the JSON body, and the headers in plaintext. Save a screenshot or the raw capture for your writeup.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add TLS.&amp;#039;&amp;#039;&amp;#039; Generate a self-signed server certificate and matching key with `openssl`. Recompile your server program against the SSL-enabled cpp-httplib by defining `CPPHTTPLIB_OPENSSL_SUPPORT` and linking `-lssl -lcrypto`. Switch `httplib::Server` to `httplib::SSLServer`, passing your cert and key paths. Switch the client to `httplib::SSLClient` and configure it to trust your self-signed cert (or, for testing only, disable verification). Get the same `/access` endpoint working over HTTPS on port 9443. &amp;#039;&amp;#039;Note: search the cpp-httplib README for the exact constructor signatures --- they are stable but worth confirming against the version you downloaded.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Inspect the wire again.&amp;#039;&amp;#039;&amp;#039; Capture the HTTPS exchange in Wireshark. Confirm that the JSON body and headers are no longer visible: you should see the TLS handshake (the `Client Hello`, `Server Hello`, `Certificate` messages should be readable as TLS metadata) followed by encrypted application data records. Note in your writeup what is still visible to an eavesdropper despite TLS (hint: at least the destination IP, port, and the SNI hostname in the handshake).&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add a simple authentication step.&amp;#039;&amp;#039;&amp;#039; Extend your HTTPS server to require an `Authorization: Bearer &amp;lt;token&amp;gt;` header. Reject any request without a valid token with HTTP 401. Choose any token value, and pass it from the client. Verify with `curl --cacert ./cert.pem -H &amp;quot;Authorization: Bearer ...&amp;quot;` that wrong tokens get 401 and the right one gets through.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Generate the WireGuard keys.&amp;#039;&amp;#039;&amp;#039; On each of the three peers --- your laptop (host), the server VM, the edge VM --- generate a private/public keypair with `wg genkey | tee privatekey | wg pubkey &amp;gt; publickey`. Collect all three public keys somewhere you can copy from. &amp;#039;&amp;#039;Treat the private keys as you would treat passwords.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Design the WireGuard topology.&amp;#039;&amp;#039;&amp;#039; Pick virtual IPs for each peer on a private subnet (e.g. `10.66.0.1` for the host, `10.66.0.2` for the server VM, `10.66.0.3` for the edge VM). Decide which peer will act as the &amp;#039;&amp;#039;rendezvous&amp;#039;&amp;#039; --- the one with a stable, reachable address that the others connect &amp;#039;&amp;#039;to&amp;#039;&amp;#039;. The host is the natural choice here because both VMs can reach it. Pick a UDP port for WireGuard (51820 is conventional).&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Write the three configs and bring them up.&amp;#039;&amp;#039;&amp;#039; Create `/etc/wireguard/wg0.conf` on each peer with the appropriate `[Interface]` and one `[Peer]` block per other peer. The host&amp;#039;s config has two `[Peer]` entries (one for each VM). Each VM&amp;#039;s config has one `[Peer]` entry pointing at the host. Bring each interface up with `sudo wg-quick up wg0`, verify with `sudo wg show`. From inside the server VM, ping `10.66.0.3` (the edge); from the edge VM, ping `10.66.0.2` (the server). Both should succeed even though no direct socket netdev connects them.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Re-run the HTTPS exercise over WireGuard.&amp;#039;&amp;#039;&amp;#039; Stop your HTTPS server, restart it bound to the WireGuard IP `10.66.0.2` instead of `172.30.0.1`. Point the client at `https://10.66.0.2:9443/access`. Verify it still works. Capture the host&amp;#039;s WireGuard UDP port in Wireshark this time --- you should see &amp;#039;&amp;#039;only&amp;#039;&amp;#039; encrypted UDP packets, with no visible TLS handshake or application protocol. Two layers of encryption, one capture: this is defense in depth.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Short writeup.&amp;#039;&amp;#039;&amp;#039; In a `WRITEUP.md` file at the root of your submission, answer:&lt;br /&gt;
## Which transport (raw TCP, HTTP, MQTT) would you use for the capstone, and why?&lt;br /&gt;
## What is still visible to an eavesdropper of HTTPS-without-VPN traffic?&lt;br /&gt;
## What is still visible to an eavesdropper of HTTPS-over-WireGuard traffic?&lt;br /&gt;
## Was the inter-VM connection for this lab actually NAT&amp;#039;d? Why or why not? (Look at your QEMU command lines and think carefully.)&lt;br /&gt;
## What would change if you replaced the QEMU edge VM with a real Raspberry Pi on your home network?&lt;br /&gt;
&lt;br /&gt;
== Bonus tasks (optional) ==&lt;br /&gt;
&lt;br /&gt;
Pick at most one. These earn no extra points but make a real difference to your project.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MQTT pub/sub.&amp;#039;&amp;#039;&amp;#039; Install `mosquitto` (broker) on the server VM and `mosquitto-clients` on the edge. Use `mosquitto_pub` and `mosquitto_sub` to send a &amp;quot;card scanned&amp;quot; event from the edge to the server over topic `lab8/door/cards`. Then write a tiny C++ subscriber using `paho-mqtt-cpp`. &amp;#039;&amp;#039;Hint:&amp;#039;&amp;#039; the broker speaks plaintext on port 1883 by default; for TLS use 8883.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Mutual TLS.&amp;#039;&amp;#039;&amp;#039; Extend your HTTPS exercise so the &amp;#039;&amp;#039;client&amp;#039;&amp;#039; also presents a certificate that the server verifies. This eliminates the need for the bearer token entirely, because possession of the private key proves identity.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Replay protection.&amp;#039;&amp;#039;&amp;#039; Add a nonce or timestamp to each `/access` request and have the server reject replays. Demonstrate that replaying a captured request with `curl` gets rejected.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Persistent WireGuard.&amp;#039;&amp;#039;&amp;#039; Configure `wg-quick` to start at boot on both VMs, so your tunnel survives a reboot.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
Submit a single archive (zip or tar) containing:&lt;br /&gt;
&lt;br /&gt;
# Source code for all programs you wrote: TCP echo client/server, HTTP server/client, HTTPS variant, plus any bonus code.&lt;br /&gt;
# A `Makefile` or `CMakeLists.txt` that builds them. Pick whichever you prefer.&lt;br /&gt;
# All three WireGuard config files (with the private keys &amp;#039;&amp;#039;redacted&amp;#039;&amp;#039;), one per peer, named clearly.&lt;br /&gt;
# Two Wireshark capture screenshots: one of plaintext HTTP showing the JSON, one of HTTPS-over-WireGuard showing only encrypted UDP.&lt;br /&gt;
# `WRITEUP.md` answering the questions in Task 11.&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;The ARM VM takes forever to boot.&amp;#039;&amp;#039; That is normal on x86 hosts without same-arch acceleration. Do not kill it; first boot is the slowest because cloud-init runs.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;The `socket` netdev does not connect the two VMs.&amp;#039;&amp;#039; Most common cause: starting the edge VM before the server VM, so there is nothing for the edge&amp;#039;s `connect=:10000` to connect to. Start the server first.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;`ping 172.30.0.2` works but my TCP server is not reachable.&amp;#039;&amp;#039; Almost always a firewall on the server VM. Either disable the firewall (`sudo ufw disable` if active) or open the port.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;Wireshark shows no traffic on loopback.&amp;#039;&amp;#039; On Linux you may need to configure permissions: `sudo dpkg-reconfigure wireshark-common` and add yourself to the `wireshark` group, then log out and back in. On macOS, ChmodBPF must be installed (the Wireshark installer prompts for this).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;cpp-httplib does not compile.&amp;#039;&amp;#039; Make sure you are using a C++17-or-later compiler (`-std=c++17`). The header is large and the first compilation takes 10+ seconds.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;TLS verification fails on the client.&amp;#039;&amp;#039; Self-signed certificates are not trusted by default. You either pass the cert path explicitly (`set_ca_cert_path`) or, for testing only, disable verification (`enable_server_certificate_verification(false)`). The lab grading does not require a properly trusted cert.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;WireGuard handshake never completes.&amp;#039;&amp;#039; The most common cause is a typo in a public key. Public keys must match exactly between peers. Second most common: the &amp;#039;&amp;#039;rendezvous&amp;#039;&amp;#039; peer&amp;#039;s UDP port is not actually reachable --- check host firewall settings and any `Endpoint` line that points at `localhost` vs an actual reachable IP.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;My VM lost the IP address on the inter-VM link after a reboot.&amp;#039;&amp;#039; Expected --- `ip addr add` is not persistent. Either re-run it after each boot, or write a `/etc/systemd/network/` config to make it permanent.&lt;br /&gt;
&lt;br /&gt;
== Looking ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week we return to the CI pipeline with the third quality gate: &amp;#039;&amp;#039;dynamic analysis&amp;#039;&amp;#039;. You will run Valgrind, AddressSanitizer, and UndefinedBehaviorSanitizer against the Oven Controller, find bugs that static analysis missed, and add a sanitizer build to your CI pipeline.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8341</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8341"/>
		<updated>2026-05-04T13:34:35Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;br /&gt;
* [[SDPT Lab 2]]&lt;br /&gt;
* [[SDPT Lab 3]]&lt;br /&gt;
* [[SDPT Lab 4]]&lt;br /&gt;
* [[SDPT Lab 5]]&lt;br /&gt;
* [[SDPT Lab 6]]&lt;br /&gt;
* [[SDPT Lab 7]]&lt;br /&gt;
* [[SDPT Lab 8]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_7&amp;diff=8339</id>
		<title>SDPT Lab 7</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_7&amp;diff=8339"/>
		<updated>2026-04-27T00:11:16Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 7 Lab Activity: Adding a Static Analysis Quality Gate =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
&lt;br /&gt;
Extend your Week 6 CI pipeline with a new &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage that runs &amp;#039;&amp;#039;&amp;#039;before&amp;#039;&amp;#039;&amp;#039; the build and blocks Merge Requests on static analysis findings. By the end of this lab your pipeline gates code on three things: it must lint cleanly, it must compile, and it must pass tests.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
In Week 6 you built a CI pipeline with at least &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; stages. Today you are adding a &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage as the first stage. A failure there skips later stages and blocks the MR.&lt;br /&gt;
&lt;br /&gt;
You will use two complementary tools. &amp;#039;&amp;#039;&amp;#039;cppcheck&amp;#039;&amp;#039;&amp;#039; is a fast, pattern-based analyzer that runs from the command line on your source tree without needing your build to succeed; its strength is speed and a low false-positive rate. &amp;#039;&amp;#039;&amp;#039;clang-tidy&amp;#039;&amp;#039;&amp;#039; is a deeper AST-based analyzer built on top of Clang, which means it understands templates, overloads, lifetimes, and modern C++ semantics. It ships hundreds of configurable checks grouped into families such as &amp;lt;code&amp;gt;bugprone-*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cert-*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cppcoreguidelines-*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;modernize-*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;performance-*&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;readability-*&amp;lt;/code&amp;gt;. The full catalog is at https://clang.llvm.org/extra/clang-tidy/checks/list.html.&lt;br /&gt;
&lt;br /&gt;
clang-tidy needs to know exactly how each file is compiled (include paths, defines, C++ standard). CMake produces that information for free if you set &amp;lt;code&amp;gt;CMAKE_EXPORT_COMPILE_COMMANDS=ON&amp;lt;/code&amp;gt;, which writes a &amp;lt;code&amp;gt;compile_commands.json&amp;lt;/code&amp;gt; to your build directory. To make clang-tidy run automatically on every compile, set the CMake variable &amp;lt;code&amp;gt;CMAKE_CXX_CLANG_TIDY&amp;lt;/code&amp;gt; to a clang-tidy command line --- CMake will then invoke clang-tidy alongside the compiler on every C++ source file. To run cppcheck from a build target, wrap it in an &amp;lt;code&amp;gt;add_custom_target&amp;lt;/code&amp;gt; definition.&lt;br /&gt;
&lt;br /&gt;
clang-tidy is configured by a &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; YAML file at the repo root. The two important keys for this lab are &amp;lt;code&amp;gt;Checks&amp;lt;/code&amp;gt; (a comma-separated glob list, prefix &amp;lt;code&amp;gt;-&amp;lt;/code&amp;gt; to disable) and &amp;lt;code&amp;gt;WarningsAsErrors&amp;lt;/code&amp;gt; (same syntax). The conventional pattern is to start with &amp;lt;code&amp;gt;-*&amp;lt;/code&amp;gt; and then re-enable only the families you want, rather than enabling everything and trying to silence the noise.&lt;br /&gt;
&lt;br /&gt;
Both tools support inline suppressions: &amp;lt;code&amp;gt;// cppcheck-suppress &amp;amp;lt;id&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;// NOLINTNEXTLINE(&amp;amp;lt;check&amp;amp;gt;)&amp;lt;/code&amp;gt;. Always pair a suppression with a comment explaining &amp;#039;&amp;#039;why&amp;#039;&amp;#039;. Unjustified suppressions are themselves a code smell.&lt;br /&gt;
&lt;br /&gt;
For tool usage refer to &amp;lt;code&amp;gt;cppcheck --help&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;man cppcheck&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;clang-tidy --help&amp;lt;/code&amp;gt;, and the check catalog linked above.&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Work on a feature branch opened from a tracked Issue. Open a Merge Request when you are ready to integrate.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Extend the build environment.&amp;#039;&amp;#039;&amp;#039; Update your &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; so the image installs both &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clang-tidy&amp;lt;/code&amp;gt;. Rebuild the image and verify both binaries respond to &amp;lt;code&amp;gt;--version&amp;lt;/code&amp;gt; from inside a container. If your runner pulls the image from a registry, push the new tag.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Configure clang-tidy.&amp;#039;&amp;#039;&amp;#039; Create &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; at the repository root. You must enable, at a minimum, the entire &amp;lt;code&amp;gt;bugprone-*&amp;lt;/code&amp;gt; family and at least two specific checks from &amp;lt;code&amp;gt;cppcoreguidelines-*&amp;lt;/code&amp;gt;. You must explicitly disable any check from those families that fires noisily on your existing code (e.g. some &amp;lt;code&amp;gt;readability-identifier-length&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;cppcoreguidelines-pro-bounds-*&amp;lt;/code&amp;gt; checks are commonly muted in embedded code). Set &amp;lt;code&amp;gt;WarningsAsErrors&amp;lt;/code&amp;gt; so any reported issue fails the build. Add a comment block at the top of the file explaining the rationale for your check selection --- this is part of the deliverable.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Wire clang-tidy into CMake.&amp;#039;&amp;#039;&amp;#039; Modify &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; so that compile commands are exported and clang-tidy runs automatically on every C++ compile. Make sure the build still works for team members who do not have clang-tidy installed locally (hint: &amp;lt;code&amp;gt;find_program&amp;lt;/code&amp;gt; can return a NOTFOUND value, and you can branch on that).&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add a cppcheck custom target.&amp;#039;&amp;#039;&amp;#039; Define a CMake custom target named &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; that runs the tool on your source tree. Required flags: at minimum &amp;lt;code&amp;gt;--enable=warning,style,performance,portability&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--error-exitcode=1&amp;lt;/code&amp;gt; (so it propagates failures), &amp;lt;code&amp;gt;--inline-suppr&amp;lt;/code&amp;gt; (so your inline suppressions are honored), and &amp;lt;code&amp;gt;--std=c++17&amp;lt;/code&amp;gt; (or whatever your project uses). Decide for yourself whether to scan or skip the build directory, the test directory, and any third-party code.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add the lint stage to GitLab CI.&amp;#039;&amp;#039;&amp;#039; Edit &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to add a new &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage as the first stage. Add a job that runs cppcheck inside your updated Docker image. The job must fail the pipeline on any cppcheck finding. clang-tidy itself does &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; need a separate CI job, since wiring it into &amp;lt;code&amp;gt;CMAKE_CXX_CLANG_TIDY&amp;lt;/code&amp;gt; means it already runs during your existing build job.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Clean up your existing code.&amp;#039;&amp;#039;&amp;#039; Push your branch and let the pipeline run. If clang-tidy or cppcheck flags real issues in the Oven Controller, fix them properly. If you genuinely believe a finding is a false positive, suppress it inline with a justification comment --- but no more than two suppressions for this lab. Three or more suppressions almost always means you should fix the underlying problem instead.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Verify the gate fires.&amp;#039;&amp;#039;&amp;#039; Once the pipeline is fully green, introduce a deliberate bug on your branch. Pick something the tools should catch: a memory leak, a null pointer dereference, an uninitialized read, a forgotten &amp;lt;code&amp;gt;delete[]&amp;lt;/code&amp;gt;, a use-after-move, a buffer overflow. Push the bug, confirm the &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; stage fails, then preserve a copy of the relevant tool output (a job-log permalink in the MR description is sufficient). Revert the deliberate bug; your final pipeline must be green.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Measure the cost.&amp;#039;&amp;#039;&amp;#039; Compare the wall-clock time of your full pipeline before and after this lab. Record both numbers and the percentage increase in the MR description, along with one sentence on whether the trade-off is worth it for this codebase. Be honest --- &amp;quot;the lint stage adds 4 minutes and we caught zero real bugs today&amp;quot; is a valid finding.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Review and merge.&amp;#039;&amp;#039;&amp;#039; Open the MR and have a teammate review it. The reviewer should specifically check: the rationale comment in &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt;, that any suppression has a justification, the visibility of the deliberate-bug pipeline run, and the cost measurement. Merge when approved.&lt;br /&gt;
&lt;br /&gt;
== Stretch tasks (optional, if you finish early) ==&lt;br /&gt;
&lt;br /&gt;
Pick at most one. These will not gain you points but will make your project measurably more professional.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tighten the rules.&amp;#039;&amp;#039;&amp;#039; Add a check from &amp;lt;code&amp;gt;cert-*&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;clang-analyzer-*&amp;lt;/code&amp;gt; and resolve all findings.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Explore MISRA.&amp;#039;&amp;#039;&amp;#039; cppcheck ships an experimental &amp;lt;code&amp;gt;misra&amp;lt;/code&amp;gt; addon. Run it against your code (you may need a rules text file --- see the cppcheck addons documentation), and report the top three findings together with the MISRA rule numbers they correspond to.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Add a pre-commit hook.&amp;#039;&amp;#039;&amp;#039; Configure either a Git pre-commit hook or the &amp;lt;code&amp;gt;pre-commit&amp;lt;/code&amp;gt; framework to run cppcheck on staged files. This catches issues before they reach CI and saves runner time.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Generate a SARIF report.&amp;#039;&amp;#039;&amp;#039; Configure clang-tidy to emit findings in SARIF format and upload it as a GitLab CI artifact. This is how findings are typically aggregated across larger projects.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
For this lab to be marked complete, your &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch must contain:&lt;br /&gt;
&lt;br /&gt;
# A &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; that installs both static analysis tools.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; file with a rationale comment and your chosen check set.&lt;br /&gt;
# A &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; that exports compile commands, hooks clang-tidy into the build, and defines a &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; custom target.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage running before the build stage.&lt;br /&gt;
# A merged MR whose linked Issue (or MR description) contains:&lt;br /&gt;
## The cost measurement from Task 8.&lt;br /&gt;
## A reference to the failed pipeline from Task 7 and the green pipeline that followed.&lt;br /&gt;
## A justification for any inline suppression added during Task 6.&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;clang-tidy reporting findings in third-party headers&amp;#039;&amp;#039;&amp;#039; (Google Test, system headers, etc.). Constrain &amp;lt;code&amp;gt;HeaderFilterRegex&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; to match only your own paths.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;cppcheck warning about missing system headers.&amp;#039;&amp;#039;&amp;#039; Add &amp;lt;code&amp;gt;--suppress=missingIncludeSystem&amp;lt;/code&amp;gt; to your invocation.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;clang-tidy producing different findings on different machines.&amp;#039;&amp;#039;&amp;#039; Almost always means &amp;lt;code&amp;gt;compile_commands.json&amp;lt;/code&amp;gt; is missing or stale --- regenerate it after every CMake configure, and make sure the file is inside the build directory clang-tidy looks at.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The pipeline timing out.&amp;#039;&amp;#039;&amp;#039; clang-tidy is significantly slower than the compiler. If the full build now exceeds your runner&amp;#039;s timeout, narrow your check set or scope &amp;lt;code&amp;gt;HeaderFilterRegex&amp;lt;/code&amp;gt; more tightly.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;&amp;quot;It works on my machine but fails in CI.&amp;quot;&amp;#039;&amp;#039;&amp;#039; Almost always means your locally installed clang-tidy version differs from the one in the Docker image. The container is the source of truth.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Suppressing checks instead of fixing code.&amp;#039;&amp;#039;&amp;#039; If you find yourself adding a third suppression, stop and reconsider. The right action is almost always to fix the code, not to silence the tool.&lt;br /&gt;
&lt;br /&gt;
== Looking ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week we leave the CI pipeline alone for one session and focus on the architecture of your capstone: how the Raspberry Pi and the VM server actually communicate. Bring your design questions about the project.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_7&amp;diff=8338</id>
		<title>SDPT Lab 7</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_7&amp;diff=8338"/>
		<updated>2026-04-27T00:10:17Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 7 Lab Activity: Adding a Static Analysis Quality Gate =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
&lt;br /&gt;
Extend your Week 6 CI pipeline with a new &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage that runs &amp;#039;&amp;#039;&amp;#039;before&amp;#039;&amp;#039;&amp;#039; the build and blocks Merge Requests on static analysis findings. By the end of this lab your pipeline gates code on three things: it must lint cleanly, it must compile, and it must pass tests.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
In Week 6 you built a CI pipeline with at least &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; stages. Today you are adding a &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage as the first stage. A failure there skips later stages and blocks the MR.&lt;br /&gt;
&lt;br /&gt;
You will use two complementary tools. &amp;#039;&amp;#039;&amp;#039;cppcheck&amp;#039;&amp;#039;&amp;#039; is a fast, pattern-based analyzer that runs from the command line on your source tree without needing your build to succeed; its strength is speed and a low false-positive rate. &amp;#039;&amp;#039;&amp;#039;clang-tidy&amp;#039;&amp;#039;&amp;#039; is a deeper AST-based analyzer built on top of Clang, which means it understands templates, overloads, lifetimes, and modern C++ semantics. It ships hundreds of configurable checks grouped into families such as &amp;lt;code&amp;gt;bugprone-*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cert-*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cppcoreguidelines-*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;modernize-*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;performance-*&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;readability-*&amp;lt;/code&amp;gt;. The full catalog is at https://clang.llvm.org/extra/clang-tidy/checks/list.html.&lt;br /&gt;
&lt;br /&gt;
clang-tidy needs to know exactly how each file is compiled (include paths, defines, C++ standard). CMake produces that information for free if you set &amp;lt;code&amp;gt;CMAKE_EXPORT_COMPILE_COMMANDS=ON&amp;lt;/code&amp;gt;, which writes a &amp;lt;code&amp;gt;compile_commands.json&amp;lt;/code&amp;gt; to your build directory. To make clang-tidy run automatically on every compile, set the CMake variable &amp;lt;code&amp;gt;CMAKE_CXX_CLANG_TIDY&amp;lt;/code&amp;gt; to a clang-tidy command line --- CMake will then invoke clang-tidy alongside the compiler on every C++ source file. To run cppcheck from a build target, wrap it in an &amp;lt;code&amp;gt;add_custom_target&amp;lt;/code&amp;gt; definition.&lt;br /&gt;
&lt;br /&gt;
clang-tidy is configured by a &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; YAML file at the repo root. The two important keys for this lab are &amp;lt;code&amp;gt;Checks&amp;lt;/code&amp;gt; (a comma-separated glob list, prefix &amp;lt;code&amp;gt;-&amp;lt;/code&amp;gt; to disable) and &amp;lt;code&amp;gt;WarningsAsErrors&amp;lt;/code&amp;gt; (same syntax). The conventional pattern is to start with &amp;lt;code&amp;gt;-*&amp;lt;/code&amp;gt; and then re-enable only the families you want, rather than enabling everything and trying to silence the noise.&lt;br /&gt;
&lt;br /&gt;
Both tools support inline suppressions: &amp;lt;code&amp;gt;// cppcheck-suppress &amp;amp;lt;id&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;// NOLINTNEXTLINE(&amp;amp;lt;check&amp;amp;gt;)&amp;lt;/code&amp;gt;. Always pair a suppression with a comment explaining &amp;#039;&amp;#039;why&amp;#039;&amp;#039;. Unjustified suppressions are themselves a code smell.&lt;br /&gt;
&lt;br /&gt;
For tool usage refer to &amp;lt;code&amp;gt;cppcheck --help&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;man cppcheck&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;clang-tidy --help&amp;lt;/code&amp;gt;, and the check catalog linked above.&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Work on a feature branch opened from a tracked Issue. Open a Merge Request when you are ready to integrate.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Extend the build environment.&amp;#039;&amp;#039;&amp;#039; Update your &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; so the image installs both &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clang-tidy&amp;lt;/code&amp;gt;. Rebuild the image and verify both binaries respond to &amp;lt;code&amp;gt;--version&amp;lt;/code&amp;gt; from inside a container. If your runner pulls the image from a registry, push the new tag.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Configure clang-tidy.&amp;#039;&amp;#039;&amp;#039; Create &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; at the repository root. You must enable, at a minimum, the entire &amp;lt;code&amp;gt;bugprone-*&amp;lt;/code&amp;gt; family and at least two specific checks from &amp;lt;code&amp;gt;cppcoreguidelines-*&amp;lt;/code&amp;gt;. You must explicitly disable any check from those families that fires noisily on your existing code (e.g. some &amp;lt;code&amp;gt;readability-identifier-length&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;cppcoreguidelines-pro-bounds-*&amp;lt;/code&amp;gt; checks are commonly muted in embedded code). Set &amp;lt;code&amp;gt;WarningsAsErrors&amp;lt;/code&amp;gt; so any reported issue fails the build. Add a comment block at the top of the file explaining the rationale for your check selection --- this is part of the deliverable.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Wire clang-tidy into CMake.&amp;#039;&amp;#039;&amp;#039; Modify &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; so that compile commands are exported and clang-tidy runs automatically on every C++ compile. Make sure the build still works for team members who do not have clang-tidy installed locally (hint: &amp;lt;code&amp;gt;find_program&amp;lt;/code&amp;gt; can return a NOTFOUND value, and you can branch on that).&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add a cppcheck custom target.&amp;#039;&amp;#039;&amp;#039; Define a CMake custom target named &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; that runs the tool on your source tree. Required flags: at minimum &amp;lt;code&amp;gt;--enable=warning,style,performance,portability&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--error-exitcode=1&amp;lt;/code&amp;gt; (so it propagates failures), &amp;lt;code&amp;gt;--inline-suppr&amp;lt;/code&amp;gt; (so your inline suppressions are honored), and &amp;lt;code&amp;gt;--std=c++17&amp;lt;/code&amp;gt; (or whatever your project uses). Decide for yourself whether to scan or skip the build directory, the test directory, and any third-party code.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Add the lint stage to GitLab CI.&amp;#039;&amp;#039;&amp;#039; Edit &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to add a new &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage as the first stage. Add a job that runs cppcheck inside your updated Docker image. The job must fail the pipeline on any cppcheck finding. clang-tidy itself does &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; need a separate CI job, since wiring it into &amp;lt;code&amp;gt;CMAKE_CXX_CLANG_TIDY&amp;lt;/code&amp;gt; means it already runs during your existing build job.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Clean up your existing code.&amp;#039;&amp;#039;&amp;#039; Push your branch and let the pipeline run. If clang-tidy or cppcheck flags real issues in the Oven Controller, fix them properly. If you genuinely believe a finding is a false positive, suppress it inline with a justification comment --- but no more than two suppressions for this lab. Three or more suppressions almost always means you should fix the underlying problem instead.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Verify the gate fires.&amp;#039;&amp;#039;&amp;#039; Once the pipeline is fully green, introduce a deliberate bug on your branch. Pick something the tools should catch: a memory leak, a null pointer dereference, an uninitialized read, a forgotten &amp;lt;code&amp;gt;delete[]&amp;lt;/code&amp;gt;, a use-after-move, a buffer overflow. Push the bug, confirm the &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; stage fails, then preserve a copy of the relevant tool output (a job-log permalink in the MR description is sufficient). Revert the deliberate bug; your final pipeline must be green.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Measure the cost.&amp;#039;&amp;#039;&amp;#039; Compare the wall-clock time of your full pipeline before and after this lab. Record both numbers and the percentage increase in the MR description, along with one sentence on whether the trade-off is worth it for this codebase. Be honest --- &amp;quot;the lint stage adds 4 minutes and we caught zero real bugs today&amp;quot; is a valid finding.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Review and merge.&amp;#039;&amp;#039;&amp;#039; Open the MR and have a teammate review it. The reviewer should specifically check: the rationale comment in &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt;, that any suppression has a justification, the visibility of the deliberate-bug pipeline run, and the cost measurement. Merge when approved.&lt;br /&gt;
&lt;br /&gt;
== Stretch tasks (optional, if you finish early) ==&lt;br /&gt;
&lt;br /&gt;
Pick at most one. These will not gain you points but will make your project measurably more professional.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tighten the rules.&amp;#039;&amp;#039;&amp;#039; Add a check from &amp;lt;code&amp;gt;cert-*&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;clang-analyzer-*&amp;lt;/code&amp;gt; and resolve all findings.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Explore MISRA.&amp;#039;&amp;#039;&amp;#039; cppcheck ships an experimental &amp;lt;code&amp;gt;misra&amp;lt;/code&amp;gt; addon. Run it against your code (you may need a rules text file --- see the cppcheck addons documentation), and report the top three findings together with the MISRA rule numbers they correspond to.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Add a pre-commit hook.&amp;#039;&amp;#039;&amp;#039; Configure either a Git pre-commit hook or the &amp;lt;code&amp;gt;pre-commit&amp;lt;/code&amp;gt; framework to run cppcheck on staged files. This catches issues before they reach CI and saves runner time.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Generate a SARIF report.&amp;#039;&amp;#039;&amp;#039; Configure clang-tidy to emit findings in SARIF format and upload it as a GitLab CI artifact. This is how findings are typically aggregated across larger projects.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
For this lab to be marked complete, your &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch must contain:&lt;br /&gt;
&lt;br /&gt;
# A &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; that installs both static analysis tools.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; file with a rationale comment and your chosen check set.&lt;br /&gt;
# A &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; that exports compile commands, hooks clang-tidy into the build, and defines a &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; custom target.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage running before the build stage.&lt;br /&gt;
# A merged MR whose linked Issue (or MR description) contains:&lt;br /&gt;
## The cost measurement from Task 8.&lt;br /&gt;
## A reference to the failed pipeline from Task 7 and the green pipeline that followed.&lt;br /&gt;
## A justification for any inline suppression added during Task 6.&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;clang-tidy reporting findings in third-party headers&amp;#039;&amp;#039;&amp;#039; (Google Test, system headers, etc.). Constrain &amp;lt;code&amp;gt;HeaderFilterRegex&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; to match only your own paths.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;cppcheck warning about missing system headers.&amp;#039;&amp;#039;&amp;#039; Add &amp;lt;code&amp;gt;--suppress=missingIncludeSystem&amp;lt;/code&amp;gt; to your invocation.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;clang-tidy producing different findings on different machines.&amp;#039;&amp;#039;&amp;#039; Almost always means &amp;lt;code&amp;gt;compile_commands.json&amp;lt;/code&amp;gt; is missing or stale --- regenerate it after every CMake configure, and make sure the file is inside the build directory clang-tidy looks at.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The pipeline timing out.&amp;#039;&amp;#039;&amp;#039; clang-tidy is significantly slower than the compiler. If the full build now exceeds your runner&amp;#039;s timeout, narrow your check set or scope &amp;lt;code&amp;gt;HeaderFilterRegex&amp;lt;/code&amp;gt; more tightly.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;&amp;quot;It works on my machine but fails in CI.&amp;quot;&amp;#039;&amp;#039;&amp;#039; Almost always means your locally installed clang-tidy version differs from the one in the Docker image. The container is the source of truth.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Suppressing checks instead of fixing code.&amp;#039;&amp;#039;&amp;#039; If you find yourself adding a third suppression, stop and reconsider. The right action is almost always to fix the code, not to silence the tool.&lt;br /&gt;
&lt;br /&gt;
== Looking ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week we leave the CI pipeline alone for one session and focus on the architecture of your capstone: how the Raspberry Pi and the VM server actually communicate. Bring your design questions about the project.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_7&amp;diff=8337</id>
		<title>SDPT Lab 7</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_7&amp;diff=8337"/>
		<updated>2026-04-26T23:58:09Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: = Week 7 Lab Activity: Adding a Static Analysis Quality Gate =  == Introduction ==  In Week 6, you built a CI pipeline that automatically compiles and tests your Oven Controller co...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 7 Lab Activity: Adding a Static Analysis Quality Gate =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In Week 6, you built a CI pipeline that automatically compiles and tests your Oven Controller code on every push. Today you will add a new stage that runs &amp;#039;&amp;#039;&amp;#039;before&amp;#039;&amp;#039;&amp;#039; the build: a &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage that uses static analysis to catch entire classes of bugs that the compiler and the unit tests cannot.&lt;br /&gt;
&lt;br /&gt;
By the end of this lab, you will have:&lt;br /&gt;
&lt;br /&gt;
# Extended your Docker build environment to include &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clang-tidy&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Created a &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; configuration file at the root of your project.&lt;br /&gt;
# Hooked clang-tidy into every CMake compile via &amp;lt;code&amp;gt;CMAKE_CXX_CLANG_TIDY&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Added a new &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage to your &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; that runs cppcheck.&lt;br /&gt;
# Verified that introducing a deliberate bug causes the pipeline to fail and block a Merge Request.&lt;br /&gt;
# Fixed the deliberate bug and watched the pipeline turn green again.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You should be starting from your finished Week 6 project, which has:&lt;br /&gt;
&lt;br /&gt;
* A working &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; for the Oven Controller.&lt;br /&gt;
* A passing Google Test suite.&lt;br /&gt;
* A &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; producing a multi-arch build environment.&lt;br /&gt;
* A &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; with at least &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; stages running on a custom GitLab Runner.&lt;br /&gt;
&lt;br /&gt;
If any of those is missing or broken, fix it before continuing. Static analysis added on top of a broken pipeline does not help anyone.&lt;br /&gt;
&lt;br /&gt;
== Step 1: Create a Feature Branch ==&lt;br /&gt;
&lt;br /&gt;
As always, do &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; work on &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. Open an Issue first (&amp;quot;Add static analysis quality gate&amp;quot;) and then create a feature branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout main&lt;br /&gt;
git pull&lt;br /&gt;
git checkout -b feature/static-analysis&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This branch will contain everything you do in this lab. At the end you will open a Merge Request just like in Week 2.&lt;br /&gt;
&lt;br /&gt;
== Step 2: Update the Dockerfile ==&lt;br /&gt;
&lt;br /&gt;
Open your &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; and add &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clang-tidy&amp;lt;/code&amp;gt; to the &amp;lt;code&amp;gt;apt-get install&amp;lt;/code&amp;gt; line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \&lt;br /&gt;
    build-essential \&lt;br /&gt;
    cmake \&lt;br /&gt;
    g++-aarch64-linux-gnu \&lt;br /&gt;
    qemu-user-static \&lt;br /&gt;
    libgtest-dev \&lt;br /&gt;
    cppcheck \&lt;br /&gt;
    clang-tidy \&lt;br /&gt;
 &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rebuild the image locally to make sure it still works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
docker build -t oven-build:lint-test .&lt;br /&gt;
docker run --rm oven-build:lint-test cppcheck --version&lt;br /&gt;
docker run --rm oven-build:lint-test clang-tidy --version&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version strings for both tools. If either command is &amp;quot;not found,&amp;quot; double-check the package names for your base image (Debian/Ubuntu use &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clang-tidy&amp;lt;/code&amp;gt;; on minimal images you may need &amp;lt;code&amp;gt;clang-tools&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;clang-tidy&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Step 3: Create the .clang-tidy Configuration File ==&lt;br /&gt;
&lt;br /&gt;
In the root of your repository (next to &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;), create a new file named exactly &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; (note the leading dot). Paste the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
---&lt;br /&gt;
Checks: &amp;gt;&lt;br /&gt;
  -*,&lt;br /&gt;
  bugprone-*,&lt;br /&gt;
  cert-*,&lt;br /&gt;
  clang-analyzer-*,&lt;br /&gt;
  cppcoreguidelines-pro-*,&lt;br /&gt;
  cppcoreguidelines-slicing,&lt;br /&gt;
  misc-unused-*,&lt;br /&gt;
  modernize-use-nullptr,&lt;br /&gt;
  modernize-use-override,&lt;br /&gt;
  modernize-use-nodiscard,&lt;br /&gt;
  performance-*,&lt;br /&gt;
  portability-*,&lt;br /&gt;
  readability-braces-around-statements,&lt;br /&gt;
  readability-misleading-indentation,&lt;br /&gt;
  readability-redundant-*,&lt;br /&gt;
  -bugprone-easily-swappable-parameters,&lt;br /&gt;
  -cppcoreguidelines-pro-bounds-pointer-arithmetic&lt;br /&gt;
&lt;br /&gt;
WarningsAsErrors: &amp;#039;*&amp;#039;&lt;br /&gt;
HeaderFilterRegex: &amp;#039;.*&amp;#039;&lt;br /&gt;
FormatStyle: &amp;#039;file&amp;#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A few notes on what this configuration does:&lt;br /&gt;
&lt;br /&gt;
* The first line &amp;lt;code&amp;gt;-*&amp;lt;/code&amp;gt; &amp;#039;&amp;#039;&amp;#039;disables&amp;#039;&amp;#039;&amp;#039; every check, then we re-enable specific families. This is the safer approach because clang-tidy ships hundreds of checks and many are too noisy.&lt;br /&gt;
* &amp;lt;code&amp;gt;WarningsAsErrors: &amp;#039;*&amp;#039;&amp;lt;/code&amp;gt; turns every remaining warning into an error. The pipeline will fail if any check fires.&lt;br /&gt;
* &amp;lt;code&amp;gt;HeaderFilterRegex: &amp;#039;.*&amp;#039;&amp;lt;/code&amp;gt; tells clang-tidy to also analyze the project&amp;#039;s headers (otherwise it skips them).&lt;br /&gt;
* The two trailing &amp;lt;code&amp;gt;-...&amp;lt;/code&amp;gt; entries &amp;#039;&amp;#039;&amp;#039;suppress&amp;#039;&amp;#039;&amp;#039; specific checks that produce too many false positives in embedded code.&lt;br /&gt;
&lt;br /&gt;
Commit this file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git add .clang-tidy&lt;br /&gt;
git commit -m &amp;quot;Add .clang-tidy configuration&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Step 4: Hook clang-tidy into CMake ==&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; and add the following near the top, &amp;#039;&amp;#039;&amp;#039;after&amp;#039;&amp;#039;&amp;#039; the &amp;lt;code&amp;gt;project(...)&amp;lt;/code&amp;gt; line but &amp;#039;&amp;#039;&amp;#039;before&amp;#039;&amp;#039;&amp;#039; any &amp;lt;code&amp;gt;add_executable&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;add_library&amp;lt;/code&amp;gt; calls:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generate compile_commands.json for tooling&lt;br /&gt;
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)&lt;br /&gt;
&lt;br /&gt;
# Enable clang-tidy on every compile&lt;br /&gt;
find_program(CLANG_TIDY_EXE NAMES clang-tidy)&lt;br /&gt;
if(CLANG_TIDY_EXE)&lt;br /&gt;
    set(CMAKE_CXX_CLANG_TIDY&lt;br /&gt;
        ${CLANG_TIDY_EXE}&lt;br /&gt;
        --config-file=${CMAKE_SOURCE_DIR}/.clang-tidy)&lt;br /&gt;
    message(STATUS &amp;quot;clang-tidy enabled: ${CLANG_TIDY_EXE}&amp;quot;)&lt;br /&gt;
else()&lt;br /&gt;
    message(WARNING &amp;quot;clang-tidy not found; lint disabled&amp;quot;)&lt;br /&gt;
endif()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reason we wrap it in &amp;lt;code&amp;gt;if(CLANG_TIDY_EXE)&amp;lt;/code&amp;gt; is so that team members who do not have clang-tidy installed locally can still build. The CI environment &amp;#039;&amp;#039;&amp;#039;does&amp;#039;&amp;#039;&amp;#039; have it, so the pipeline will still enforce it.&lt;br /&gt;
&lt;br /&gt;
Test it locally:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm -rf build&lt;br /&gt;
docker run --rm -v $PWD:/work -w /work oven-build:lint-test \&lt;br /&gt;
    bash -c &amp;quot;cmake -B build &amp;amp;&amp;amp; cmake --build build&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see &amp;lt;code&amp;gt;-- clang-tidy enabled: /usr/bin/clang-tidy&amp;lt;/code&amp;gt; in the configure step, and during the build clang-tidy runs alongside the compiler. If your code is clean, the build still succeeds. If clang-tidy finds something, the build fails with a clang-tidy error message.&lt;br /&gt;
&lt;br /&gt;
== Step 5: Add a Cppcheck Custom Target ==&lt;br /&gt;
&lt;br /&gt;
cppcheck does not need CMake to drive it (it parses source directly), but adding a CMake target makes it convenient to run locally. Append this to &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Cppcheck target (optional locally, mandatory in CI)&lt;br /&gt;
find_program(CPPCHECK_EXE NAMES cppcheck)&lt;br /&gt;
if(CPPCHECK_EXE)&lt;br /&gt;
    add_custom_target(cppcheck&lt;br /&gt;
        COMMAND ${CPPCHECK_EXE}&lt;br /&gt;
            --enable=warning,style,performance,portability&lt;br /&gt;
            --inline-suppr&lt;br /&gt;
            --error-exitcode=1&lt;br /&gt;
            --suppress=missingIncludeSystem&lt;br /&gt;
            --std=c++17&lt;br /&gt;
            -I ${CMAKE_SOURCE_DIR}/include&lt;br /&gt;
            ${CMAKE_SOURCE_DIR}/src&lt;br /&gt;
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}&lt;br /&gt;
        COMMENT &amp;quot;Running cppcheck on src/&amp;quot;)&lt;br /&gt;
endif()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Adjust the &amp;lt;code&amp;gt;-I&amp;lt;/code&amp;gt; include path and the source path to match your project layout if it differs.&lt;br /&gt;
&lt;br /&gt;
You can now run cppcheck locally with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cmake --build build --target cppcheck&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If your code is clean, the command prints nothing and exits with status 0.&lt;br /&gt;
&lt;br /&gt;
Commit your CMake changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git add CMakeLists.txt Dockerfile&lt;br /&gt;
git commit -m &amp;quot;Wire clang-tidy and cppcheck into the build&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Step 6: Add the lint Stage to GitLab CI ==&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt;. Add &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; as the &amp;#039;&amp;#039;&amp;#039;first&amp;#039;&amp;#039;&amp;#039; stage in your &amp;lt;code&amp;gt;stages:&amp;lt;/code&amp;gt; list:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
stages:&lt;br /&gt;
  - lint&lt;br /&gt;
  - build&lt;br /&gt;
  - test&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then add a new job that runs cppcheck. Place it above your existing &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; job:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cppcheck:&lt;br /&gt;
  stage: lint&lt;br /&gt;
  image: $CI_REGISTRY_IMAGE/oven-build:latest&lt;br /&gt;
  script:&lt;br /&gt;
    - cppcheck&lt;br /&gt;
        --enable=warning,style,performance,portability&lt;br /&gt;
        --inline-suppr&lt;br /&gt;
        --error-exitcode=1&lt;br /&gt;
        --suppress=missingIncludeSystem&lt;br /&gt;
        --std=c++17&lt;br /&gt;
        -I include&lt;br /&gt;
        src&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: clang-tidy is &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; a separate CI job. Because we wired it into &amp;lt;code&amp;gt;CMAKE_CXX_CLANG_TIDY&amp;lt;/code&amp;gt;, it runs during the existing &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; job, on every translation unit. If clang-tidy reports an error, the build job fails just as if the compiler had failed. This is exactly the behavior we want: one pipeline run, multiple gates.&lt;br /&gt;
&lt;br /&gt;
Commit and push your branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git add .gitlab-ci.yml&lt;br /&gt;
git commit -m &amp;quot;Add lint stage running cppcheck&amp;quot;&lt;br /&gt;
git push -u origin feature/static-analysis&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open a Merge Request from &amp;lt;code&amp;gt;feature/static-analysis&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. The pipeline should run, the new &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage should appear, and (assuming your code is clean) all stages should pass.&lt;br /&gt;
&lt;br /&gt;
== Step 7: Trigger a Failure on Purpose ==&lt;br /&gt;
&lt;br /&gt;
Quality gates are only useful if they actually catch things. Let us prove ours does.&lt;br /&gt;
&lt;br /&gt;
Pick any &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; file in your project --- for example &amp;lt;code&amp;gt;src/OvenController.cpp&amp;lt;/code&amp;gt;. Add the following intentionally broken function near the top of the file, &amp;#039;&amp;#039;&amp;#039;but inside the same namespace and class&amp;#039;&amp;#039;&amp;#039; so it actually compiles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Intentional bug for Week 7 lab. Remove before merge.&lt;br /&gt;
void OvenController::leakyDiagnostic() {&lt;br /&gt;
    int* readings = new int[100];&lt;br /&gt;
    if (sensors_.empty()) {&lt;br /&gt;
        return;   // &amp;lt;-- LEAK: never delete[] readings&lt;br /&gt;
    }&lt;br /&gt;
    for (int i = 0; i &amp;lt; 100; ++i) {&lt;br /&gt;
        readings[i] = i;&lt;br /&gt;
    }&lt;br /&gt;
    delete[] readings;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also declare it in the corresponding header. Commit and push:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git add src/OvenController.cpp include/OvenController.hpp&lt;br /&gt;
git commit -m &amp;quot;Add deliberate leak (lab demo, will revert)&amp;quot;&lt;br /&gt;
git push&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now watch your Merge Request. The new pipeline run should:&lt;br /&gt;
&lt;br /&gt;
# Start the &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
# cppcheck reports the leak and exits non-zero.&lt;br /&gt;
# The &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; job turns red.&lt;br /&gt;
# The &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; jobs are skipped (because &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; failed).&lt;br /&gt;
# The Merge Request is automatically blocked from merging.&lt;br /&gt;
&lt;br /&gt;
Click into the failed job and read the cppcheck output. You should see something close to:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
src/OvenController.cpp:42:5: error: Memory leak: readings [memleak]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is exactly what should happen. The pipeline did its job.&lt;br /&gt;
&lt;br /&gt;
== Step 8: Fix and Merge ==&lt;br /&gt;
&lt;br /&gt;
Revert the deliberate bug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git revert HEAD&lt;br /&gt;
git push&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Or remove the function manually and commit. Either is fine.)&lt;br /&gt;
&lt;br /&gt;
The new pipeline should pass all stages: &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; green, &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; green (with clang-tidy clean), &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; green. Merge the MR via GitLab.&lt;br /&gt;
&lt;br /&gt;
You now have a working, multi-stage CI pipeline that enforces both unit tests &amp;#039;&amp;#039;&amp;#039;and&amp;#039;&amp;#039;&amp;#039; static analysis on every change to the codebase.&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
To be marked as complete, your &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch must contain:&lt;br /&gt;
&lt;br /&gt;
# An updated &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clang-tidy&amp;lt;/code&amp;gt; installed.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; configuration file at the repo root.&lt;br /&gt;
# A &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; that exports &amp;lt;code&amp;gt;compile_commands.json&amp;lt;/code&amp;gt;, sets &amp;lt;code&amp;gt;CMAKE_CXX_CLANG_TIDY&amp;lt;/code&amp;gt;, and defines a &amp;lt;code&amp;gt;cppcheck&amp;lt;/code&amp;gt; custom target.&lt;br /&gt;
# A &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;lint&amp;lt;/code&amp;gt; stage running cppcheck &amp;#039;&amp;#039;&amp;#039;before&amp;#039;&amp;#039;&amp;#039; the &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
# A merged Merge Request whose pipeline shows &amp;#039;&amp;#039;&amp;#039;four&amp;#039;&amp;#039;&amp;#039; green jobs (lint, build, test, plus any others you already had).&lt;br /&gt;
# Evidence in the MR&amp;#039;s pipeline history of &amp;#039;&amp;#039;&amp;#039;at least one failed pipeline&amp;#039;&amp;#039;&amp;#039; caused by the deliberate bug, followed by the fix.&lt;br /&gt;
&lt;br /&gt;
== Common Issues ==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;clang-tidy reports many warnings on third-party headers (Google Test, system includes).&amp;#039;&amp;#039;&lt;br /&gt;
* Make sure &amp;lt;code&amp;gt;HeaderFilterRegex&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;.clang-tidy&amp;lt;/code&amp;gt; only matches your own headers, e.g. &amp;lt;code&amp;gt;&amp;#039;^src/|^include/&amp;#039;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;cppcheck complains about missing system headers.&amp;#039;&amp;#039;&lt;br /&gt;
* That is what &amp;lt;code&amp;gt;--suppress=missingIncludeSystem&amp;lt;/code&amp;gt; is for. Make sure you kept that flag.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;clang-tidy fails because it cannot find compile flags.&amp;#039;&amp;#039;&lt;br /&gt;
* Confirm that &amp;lt;code&amp;gt;set(CMAKE_EXPORT_COMPILE_COMMANDS ON)&amp;lt;/code&amp;gt; is in &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;, that &amp;lt;code&amp;gt;build/compile_commands.json&amp;lt;/code&amp;gt; exists after configure, and that you ran CMake before clang-tidy.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;The pipeline runs forever, then times out.&amp;#039;&amp;#039;&lt;br /&gt;
* clang-tidy is significantly slower than the compiler. If a full build now takes more than 10 minutes, consider narrowing your &amp;lt;code&amp;gt;Checks:&amp;lt;/code&amp;gt; list. Start tight, loosen as you learn which checks pull their weight.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;My capstone project codebase already has dozens of warnings.&amp;#039;&amp;#039;&lt;br /&gt;
* That is normal for an existing codebase. Two strategies: (1) fix them all in one MR, or (2) configure clang-tidy to warn-but-not-fail until you have cleaned things up. Option (1) is cleaner. Option (2) is realistic when you inherit legacy code.&lt;br /&gt;
&lt;br /&gt;
== Looking Ahead ==&lt;br /&gt;
&lt;br /&gt;
Next week we leave the CI pipeline alone and turn to the &amp;#039;&amp;#039;&amp;#039;system architecture&amp;#039;&amp;#039;&amp;#039; of your capstone: how does your Raspberry Pi actually talk to the VM server? Sockets, REST, MQTT, and the design trade-offs between them.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8336</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8336"/>
		<updated>2026-04-26T23:58:04Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;br /&gt;
* [[SDPT Lab 2]]&lt;br /&gt;
* [[SDPT Lab 3]]&lt;br /&gt;
* [[SDPT Lab 4]]&lt;br /&gt;
* [[SDPT Lab 5]]&lt;br /&gt;
* [[SDPT Lab 6]]&lt;br /&gt;
* [[SDPT Lab 7]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8330</id>
		<title>SDPT Lab 6</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8330"/>
		<updated>2026-04-20T17:49:47Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 6 Lab Activity: CI/CD Pipelines &amp;amp; Custom Runners =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
Today, we automate everything. You will transition from compiling code on your laptop to architecting a professional CI/CD pipeline. &lt;br /&gt;
&lt;br /&gt;
We will accomplish this in six phases:&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Repository Setup:&amp;#039;&amp;#039;&amp;#039; Migrating your code to GitLab.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Infrastructure:&amp;#039;&amp;#039;&amp;#039; Spinning up and registering your own local GitLab Runner via Docker.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Integration (Build):&amp;#039;&amp;#039;&amp;#039; Writing your first CI job and generating Artifacts.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Integration (Test):&amp;#039;&amp;#039;&amp;#039; Consuming Artifacts and testing via QEMU.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Deployment (CD):&amp;#039;&amp;#039;&amp;#039; Creating a simulated OTA firmware release restricted to the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cleanup:&amp;#039;&amp;#039;&amp;#039; Deregistering and destroying your local runner.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 1: Repository Setup ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Create a Project:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Log into GitLab and create a new blank project named &amp;lt;code&amp;gt;sdpt-smart-oven&amp;lt;/code&amp;gt;. Uncheck &amp;quot;Initialize repository with a README&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Push Your Code:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Open your terminal on your laptop, navigate to your Week 5 project folder, and push your code to this new repository.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git init&lt;br /&gt;
git branch -m main&lt;br /&gt;
git remote add origin https://gitlab.cs.pub.ro/&amp;lt;your-username&amp;gt;/sdpt-smart-oven.git&lt;br /&gt;
git add .&lt;br /&gt;
git commit -m &amp;quot;Initial commit: Oven Controller with CMake and Docker&amp;quot;&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 2: Registering a Local Runner ==&lt;br /&gt;
GitLab provides shared runners, but embedded systems often require custom hardware or specific toolchains. We will host our own Runner!&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Get Your Registration Token:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
In your GitLab project, go to &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;CI/CD&amp;#039;&amp;#039;&amp;#039;. Expand the &amp;#039;&amp;#039;&amp;#039;Runners&amp;#039;&amp;#039;&amp;#039; section. Under &amp;quot;Project runners&amp;quot;, click &amp;quot;New project runner&amp;quot;. Add the tag &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt; and click Create. Copy the &amp;#039;&amp;#039;&amp;#039;registration token&amp;#039;&amp;#039;&amp;#039; it gives you.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Start the Runner via Docker:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
On your laptop terminal, run a background Docker container to act as your runner. (We mount the Docker socket so the runner can spawn its own containers!)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run -d --name my-local-runner --restart always -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;3. Register the Runner:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Now, execute the registration command inside the running container:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker exec -it my-local-runner gitlab-runner register&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;GitLab instance URL:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;https://gitlab.cs.pub.ro/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Registration token:&amp;#039;&amp;#039;&amp;#039; (Paste your token from step 1)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Description:&amp;#039;&amp;#039;&amp;#039; My Laptop Runner&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tags:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Executor:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Default image:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;ubuntu:22.04&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Refresh your GitLab Runners page. You should see a green circle indicating your local runner is alive and listening for jobs!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 3: The Build Stage &amp;amp; Artifacts ==&lt;br /&gt;
We will now tell your Runner how to build our code. Create a file named exactly &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; in your project root.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 1):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Image:&amp;#039;&amp;#039;&amp;#039; Set &amp;lt;code&amp;gt;image:&amp;lt;/code&amp;gt; to the ARM Docker image you built last week.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Stages:&amp;#039;&amp;#039;&amp;#039; Define three stages: &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Build Job:&amp;#039;&amp;#039;&amp;#039; Create a job named &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Assign it to the &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
#* Use &amp;lt;code&amp;gt;tags: [local-embedded]&amp;lt;/code&amp;gt; to force this job to run on YOUR laptop&amp;#039;s runner.&lt;br /&gt;
#* In the &amp;lt;code&amp;gt;script&amp;lt;/code&amp;gt;, run CMake for &amp;lt;code&amp;gt;aarch64&amp;lt;/code&amp;gt; and run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Create &amp;lt;code&amp;gt;artifacts&amp;lt;/code&amp;gt; to save the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory (expire in 1 hour).&lt;br /&gt;
&lt;br /&gt;
Commit and push. Watch the pipeline in GitLab. Your laptop&amp;#039;s fan might spin up because *your* Docker daemon is doing the heavy lifting!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 4: The Test Stage &amp;amp; Merge Checks ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 2):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Add a job named &amp;lt;code&amp;gt;verify_logic&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Require the artifacts from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Navigate to &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; and execute tests using QEMU (&amp;lt;code&amp;gt;qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Test the Block:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Go to GitLab &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Merge Requests&amp;#039;&amp;#039;&amp;#039; -&amp;gt; Check &amp;quot;Pipelines must succeed&amp;quot;.&lt;br /&gt;
# Create a new branch: &amp;lt;code&amp;gt;git checkout -b feature/broken-math&amp;lt;/code&amp;gt;&lt;br /&gt;
# Break an assertion in your C++ tests and push the branch.&lt;br /&gt;
# Open a Merge Request. Watch the test stage fail and observe the Merge button physically lock you out! Fix the code, push again, and Merge it.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 5: Continuous Deployment (CD) ==&lt;br /&gt;
Once the code hits the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch, we want to handle two different types of deployments: an automated OTA release (Pull), and an on-demand Edge deployment (Push).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 3): Automated OTA Release&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Add a job named &amp;lt;code&amp;gt;release_ota_firmware&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Pull from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Rename your binary to a release format and simulate cryptographically signing it:&lt;br /&gt;
#* &amp;lt;code&amp;gt;mv build/unit_tests build/firmware_v1.bin&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;CRYPTOGRAPHIC_SIGNATURE_OK&amp;quot; &amp;gt;&amp;gt; build/firmware_v1.bin&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Rules:&amp;#039;&amp;#039;&amp;#039; We ONLY want to release firmware automatically from the main branch! Add a &amp;lt;code&amp;gt;rules:&amp;lt;/code&amp;gt; section with &amp;lt;code&amp;gt;- if: &amp;#039;$CI_COMMIT_BRANCH == &amp;quot;main&amp;quot;&amp;#039;&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Artifacts:&amp;#039;&amp;#039;&amp;#039; Save &amp;lt;code&amp;gt;build/firmware_v1.bin&amp;lt;/code&amp;gt; as an artifact that never expires.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 4): On-Demand Push Deployment&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Sometimes we need to instantly push an update to a specific machine (e.g., a prototype in the lab) without waiting for it to poll. We will simulate an SSH deployment using pipeline variables. &lt;br /&gt;
&lt;br /&gt;
Add another job named &amp;lt;code&amp;gt;deploy_to_edge_device&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Pull from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Rules:&amp;#039;&amp;#039;&amp;#039; We want this to be an &amp;quot;On-Demand&amp;quot; job that requires a human to click a play button. Add a &amp;lt;code&amp;gt;rules:&amp;lt;/code&amp;gt; section with &amp;lt;code&amp;gt;- when: manual&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Simulate securely pushing the binary to a specific IP address using an environment variable (&amp;lt;code&amp;gt;$TARGET_IP&amp;lt;/code&amp;gt;). Do not hardcode an IP here; we will inject it later!&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;Connecting to Edge Device at $TARGET_IP...&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;scp build/unit_tests admin@$TARGET_IP:/opt/smart-oven/bin/&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;Deployment to $TARGET_IP successful!&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Test the Deployments:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Push your code to &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. &lt;br /&gt;
# You will see the &amp;lt;code&amp;gt;release_ota_firmware&amp;lt;/code&amp;gt; job run automatically. &lt;br /&gt;
# The &amp;lt;code&amp;gt;deploy_to_edge_device&amp;lt;/code&amp;gt; job will be paused (marked with a &amp;quot;Play&amp;quot; icon). &lt;br /&gt;
# Click the Play icon. GitLab will take you to a new screen asking if you want to inject any environment variables.&lt;br /&gt;
# Add a variable with the Key &amp;lt;code&amp;gt;TARGET_IP&amp;lt;/code&amp;gt; and the Value &amp;lt;code&amp;gt;192.168.1.50&amp;lt;/code&amp;gt; (or any dummy IP address you prefer).&lt;br /&gt;
# Click &amp;quot;Run job&amp;quot; and check the terminal output to see your variable successfully injected into the simulated SSH command!&lt;br /&gt;
&lt;br /&gt;
== Phase 6: Cleanup ==&lt;br /&gt;
To prevent your runner from polling GitLab forever and draining your laptop battery, gracefully shut it down and remove it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker stop my-local-runner&lt;br /&gt;
docker rm my-local-runner&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the GitLab UI, go back to Settings -&amp;gt; CI/CD -&amp;gt; Runners, and delete the offline runner.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Assignment Submission ===&lt;br /&gt;
Upload &amp;#039;&amp;#039;&amp;#039;ONLY&amp;#039;&amp;#039;&amp;#039; your finalized &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to the Moodle VPL assignment. The automated grading server will analyze your YAML syntax to ensure you correctly configured the stages, artifacts, custom runner routing, and deployment rules.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8329</id>
		<title>SDPT Lab 6</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8329"/>
		<updated>2026-04-19T17:27:43Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Phase 5: Continuous Deployment (CD) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 6 Lab Activity: CI/CD Pipelines &amp;amp; Custom Runners =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
Today, we automate everything. You will transition from compiling code on your laptop to architecting a professional CI/CD pipeline. &lt;br /&gt;
&lt;br /&gt;
We will accomplish this in six phases:&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Repository Setup:&amp;#039;&amp;#039;&amp;#039; Migrating your code to GitLab.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Infrastructure:&amp;#039;&amp;#039;&amp;#039; Spinning up and registering your own local GitLab Runner via Docker.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Integration (Build):&amp;#039;&amp;#039;&amp;#039; Writing your first CI job and generating Artifacts.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Integration (Test):&amp;#039;&amp;#039;&amp;#039; Consuming Artifacts and testing via QEMU.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Deployment (CD):&amp;#039;&amp;#039;&amp;#039; Creating a simulated OTA firmware release restricted to the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cleanup:&amp;#039;&amp;#039;&amp;#039; Deregistering and destroying your local runner.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 1: Repository Setup ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Create a Project:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Log into GitLab and create a new blank project named &amp;lt;code&amp;gt;sdpt-smart-oven&amp;lt;/code&amp;gt;. Uncheck &amp;quot;Initialize repository with a README&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Push Your Code:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Open your terminal on your laptop, navigate to your Week 5 project folder, and push your code to this new repository.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git init&lt;br /&gt;
git branch -m main&lt;br /&gt;
git remote add origin https://gitlab.com/&amp;lt;your-username&amp;gt;/sdpt-smart-oven.git&lt;br /&gt;
git add .&lt;br /&gt;
git commit -m &amp;quot;Initial commit: Oven Controller with CMake and Docker&amp;quot;&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 2: Registering a Local Runner ==&lt;br /&gt;
GitLab provides shared runners, but embedded systems often require custom hardware or specific toolchains. We will host our own Runner!&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Get Your Registration Token:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
In your GitLab project, go to &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;CI/CD&amp;#039;&amp;#039;&amp;#039;. Expand the &amp;#039;&amp;#039;&amp;#039;Runners&amp;#039;&amp;#039;&amp;#039; section. Under &amp;quot;Project runners&amp;quot;, click &amp;quot;New project runner&amp;quot;. Add the tag &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt; and click Create. Copy the &amp;#039;&amp;#039;&amp;#039;registration token&amp;#039;&amp;#039;&amp;#039; it gives you.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Start the Runner via Docker:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
On your laptop terminal, run a background Docker container to act as your runner. (We mount the Docker socket so the runner can spawn its own containers!)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run -d --name my-local-runner --restart always -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;3. Register the Runner:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Now, execute the registration command inside the running container:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker exec -it my-local-runner gitlab-runner register&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;GitLab instance URL:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;https://gitlab.com/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Registration token:&amp;#039;&amp;#039;&amp;#039; (Paste your token from step 1)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Description:&amp;#039;&amp;#039;&amp;#039; My Laptop Runner&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tags:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Executor:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Default image:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;ubuntu:22.04&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Refresh your GitLab Runners page. You should see a green circle indicating your local runner is alive and listening for jobs!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 3: The Build Stage &amp;amp; Artifacts ==&lt;br /&gt;
We will now tell your Runner how to build our code. Create a file named exactly &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; in your project root.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 1):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Image:&amp;#039;&amp;#039;&amp;#039; Set &amp;lt;code&amp;gt;image:&amp;lt;/code&amp;gt; to the ARM Docker image you built last week.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Stages:&amp;#039;&amp;#039;&amp;#039; Define three stages: &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Build Job:&amp;#039;&amp;#039;&amp;#039; Create a job named &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Assign it to the &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
#* Use &amp;lt;code&amp;gt;tags: [local-embedded]&amp;lt;/code&amp;gt; to force this job to run on YOUR laptop&amp;#039;s runner.&lt;br /&gt;
#* In the &amp;lt;code&amp;gt;script&amp;lt;/code&amp;gt;, run CMake for &amp;lt;code&amp;gt;aarch64&amp;lt;/code&amp;gt; and run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Create &amp;lt;code&amp;gt;artifacts&amp;lt;/code&amp;gt; to save the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory (expire in 1 hour).&lt;br /&gt;
&lt;br /&gt;
Commit and push. Watch the pipeline in GitLab. Your laptop&amp;#039;s fan might spin up because *your* Docker daemon is doing the heavy lifting!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 4: The Test Stage &amp;amp; Merge Checks ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 2):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Add a job named &amp;lt;code&amp;gt;verify_logic&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Require the artifacts from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Navigate to &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; and execute tests using QEMU (&amp;lt;code&amp;gt;qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Test the Block:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Go to GitLab &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Merge Requests&amp;#039;&amp;#039;&amp;#039; -&amp;gt; Check &amp;quot;Pipelines must succeed&amp;quot;.&lt;br /&gt;
# Create a new branch: &amp;lt;code&amp;gt;git checkout -b feature/broken-math&amp;lt;/code&amp;gt;&lt;br /&gt;
# Break an assertion in your C++ tests and push the branch.&lt;br /&gt;
# Open a Merge Request. Watch the test stage fail and observe the Merge button physically lock you out! Fix the code, push again, and Merge it.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 5: Continuous Deployment (CD) ==&lt;br /&gt;
Once the code hits the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch, we want to handle two different types of deployments: an automated OTA release (Pull), and an on-demand Edge deployment (Push).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 3): Automated OTA Release&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Add a job named &amp;lt;code&amp;gt;release_ota_firmware&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Pull from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Rename your binary to a release format and simulate cryptographically signing it:&lt;br /&gt;
#* &amp;lt;code&amp;gt;mv build/unit_tests build/firmware_v1.bin&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;CRYPTOGRAPHIC_SIGNATURE_OK&amp;quot; &amp;gt;&amp;gt; build/firmware_v1.bin&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Rules:&amp;#039;&amp;#039;&amp;#039; We ONLY want to release firmware automatically from the main branch! Add a &amp;lt;code&amp;gt;rules:&amp;lt;/code&amp;gt; section with &amp;lt;code&amp;gt;- if: &amp;#039;$CI_COMMIT_BRANCH == &amp;quot;main&amp;quot;&amp;#039;&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Artifacts:&amp;#039;&amp;#039;&amp;#039; Save &amp;lt;code&amp;gt;build/firmware_v1.bin&amp;lt;/code&amp;gt; as an artifact that never expires.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 4): On-Demand Push Deployment&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Sometimes we need to instantly push an update to a specific machine (e.g., a prototype in the lab) without waiting for it to poll. We will simulate an SSH deployment using pipeline variables. &lt;br /&gt;
&lt;br /&gt;
Add another job named &amp;lt;code&amp;gt;deploy_to_edge_device&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Pull from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Rules:&amp;#039;&amp;#039;&amp;#039; We want this to be an &amp;quot;On-Demand&amp;quot; job that requires a human to click a play button. Add a &amp;lt;code&amp;gt;rules:&amp;lt;/code&amp;gt; section with &amp;lt;code&amp;gt;- when: manual&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Simulate securely pushing the binary to a specific IP address using an environment variable (&amp;lt;code&amp;gt;$TARGET_IP&amp;lt;/code&amp;gt;). Do not hardcode an IP here; we will inject it later!&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;Connecting to Edge Device at $TARGET_IP...&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;scp build/unit_tests admin@$TARGET_IP:/opt/smart-oven/bin/&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;Deployment to $TARGET_IP successful!&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Test the Deployments:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Push your code to &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. &lt;br /&gt;
# You will see the &amp;lt;code&amp;gt;release_ota_firmware&amp;lt;/code&amp;gt; job run automatically. &lt;br /&gt;
# The &amp;lt;code&amp;gt;deploy_to_edge_device&amp;lt;/code&amp;gt; job will be paused (marked with a &amp;quot;Play&amp;quot; icon). &lt;br /&gt;
# Click the Play icon. GitLab will take you to a new screen asking if you want to inject any environment variables.&lt;br /&gt;
# Add a variable with the Key &amp;lt;code&amp;gt;TARGET_IP&amp;lt;/code&amp;gt; and the Value &amp;lt;code&amp;gt;192.168.1.50&amp;lt;/code&amp;gt; (or any dummy IP address you prefer).&lt;br /&gt;
# Click &amp;quot;Run job&amp;quot; and check the terminal output to see your variable successfully injected into the simulated SSH command!&lt;br /&gt;
&lt;br /&gt;
== Phase 6: Cleanup ==&lt;br /&gt;
To prevent your runner from polling GitLab forever and draining your laptop battery, gracefully shut it down and remove it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker stop my-local-runner&lt;br /&gt;
docker rm my-local-runner&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the GitLab UI, go back to Settings -&amp;gt; CI/CD -&amp;gt; Runners, and delete the offline runner.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Assignment Submission ===&lt;br /&gt;
Upload &amp;#039;&amp;#039;&amp;#039;ONLY&amp;#039;&amp;#039;&amp;#039; your finalized &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to the Moodle VPL assignment. The automated grading server will analyze your YAML syntax to ensure you correctly configured the stages, artifacts, custom runner routing, and deployment rules.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8328</id>
		<title>SDPT Lab 6</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8328"/>
		<updated>2026-04-19T17:08:20Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Phase 5: Continuous Deployment (CD) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 6 Lab Activity: CI/CD Pipelines &amp;amp; Custom Runners =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
Today, we automate everything. You will transition from compiling code on your laptop to architecting a professional CI/CD pipeline. &lt;br /&gt;
&lt;br /&gt;
We will accomplish this in six phases:&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Repository Setup:&amp;#039;&amp;#039;&amp;#039; Migrating your code to GitLab.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Infrastructure:&amp;#039;&amp;#039;&amp;#039; Spinning up and registering your own local GitLab Runner via Docker.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Integration (Build):&amp;#039;&amp;#039;&amp;#039; Writing your first CI job and generating Artifacts.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Integration (Test):&amp;#039;&amp;#039;&amp;#039; Consuming Artifacts and testing via QEMU.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Deployment (CD):&amp;#039;&amp;#039;&amp;#039; Creating a simulated OTA firmware release restricted to the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cleanup:&amp;#039;&amp;#039;&amp;#039; Deregistering and destroying your local runner.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 1: Repository Setup ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Create a Project:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Log into GitLab and create a new blank project named &amp;lt;code&amp;gt;sdpt-smart-oven&amp;lt;/code&amp;gt;. Uncheck &amp;quot;Initialize repository with a README&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Push Your Code:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Open your terminal on your laptop, navigate to your Week 5 project folder, and push your code to this new repository.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git init&lt;br /&gt;
git branch -m main&lt;br /&gt;
git remote add origin https://gitlab.com/&amp;lt;your-username&amp;gt;/sdpt-smart-oven.git&lt;br /&gt;
git add .&lt;br /&gt;
git commit -m &amp;quot;Initial commit: Oven Controller with CMake and Docker&amp;quot;&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 2: Registering a Local Runner ==&lt;br /&gt;
GitLab provides shared runners, but embedded systems often require custom hardware or specific toolchains. We will host our own Runner!&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Get Your Registration Token:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
In your GitLab project, go to &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;CI/CD&amp;#039;&amp;#039;&amp;#039;. Expand the &amp;#039;&amp;#039;&amp;#039;Runners&amp;#039;&amp;#039;&amp;#039; section. Under &amp;quot;Project runners&amp;quot;, click &amp;quot;New project runner&amp;quot;. Add the tag &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt; and click Create. Copy the &amp;#039;&amp;#039;&amp;#039;registration token&amp;#039;&amp;#039;&amp;#039; it gives you.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Start the Runner via Docker:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
On your laptop terminal, run a background Docker container to act as your runner. (We mount the Docker socket so the runner can spawn its own containers!)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run -d --name my-local-runner --restart always -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;3. Register the Runner:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Now, execute the registration command inside the running container:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker exec -it my-local-runner gitlab-runner register&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;GitLab instance URL:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;https://gitlab.com/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Registration token:&amp;#039;&amp;#039;&amp;#039; (Paste your token from step 1)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Description:&amp;#039;&amp;#039;&amp;#039; My Laptop Runner&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tags:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Executor:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Default image:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;ubuntu:22.04&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Refresh your GitLab Runners page. You should see a green circle indicating your local runner is alive and listening for jobs!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 3: The Build Stage &amp;amp; Artifacts ==&lt;br /&gt;
We will now tell your Runner how to build our code. Create a file named exactly &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; in your project root.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 1):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Image:&amp;#039;&amp;#039;&amp;#039; Set &amp;lt;code&amp;gt;image:&amp;lt;/code&amp;gt; to the ARM Docker image you built last week.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Stages:&amp;#039;&amp;#039;&amp;#039; Define three stages: &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Build Job:&amp;#039;&amp;#039;&amp;#039; Create a job named &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Assign it to the &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
#* Use &amp;lt;code&amp;gt;tags: [local-embedded]&amp;lt;/code&amp;gt; to force this job to run on YOUR laptop&amp;#039;s runner.&lt;br /&gt;
#* In the &amp;lt;code&amp;gt;script&amp;lt;/code&amp;gt;, run CMake for &amp;lt;code&amp;gt;aarch64&amp;lt;/code&amp;gt; and run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Create &amp;lt;code&amp;gt;artifacts&amp;lt;/code&amp;gt; to save the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory (expire in 1 hour).&lt;br /&gt;
&lt;br /&gt;
Commit and push. Watch the pipeline in GitLab. Your laptop&amp;#039;s fan might spin up because *your* Docker daemon is doing the heavy lifting!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 4: The Test Stage &amp;amp; Merge Checks ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 2):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Add a job named &amp;lt;code&amp;gt;verify_logic&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Require the artifacts from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Navigate to &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; and execute tests using QEMU (&amp;lt;code&amp;gt;qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Test the Block:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Go to GitLab &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Merge Requests&amp;#039;&amp;#039;&amp;#039; -&amp;gt; Check &amp;quot;Pipelines must succeed&amp;quot;.&lt;br /&gt;
# Create a new branch: &amp;lt;code&amp;gt;git checkout -b feature/broken-math&amp;lt;/code&amp;gt;&lt;br /&gt;
# Break an assertion in your C++ tests and push the branch.&lt;br /&gt;
# Open a Merge Request. Watch the test stage fail and observe the Merge button physically lock you out! Fix the code, push again, and Merge it.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 5: Continuous Deployment (CD) ==&lt;br /&gt;
Once the code hits the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch, we want to handle two different types of deployments: an automated OTA release (Pull), and an on-demand Edge deployment (Push).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 3): Automated OTA Release&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Add a job named &amp;lt;code&amp;gt;release_ota_firmware&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Pull from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Rename your binary to a release format and simulate cryptographically signing it:&lt;br /&gt;
#* &amp;lt;code&amp;gt;mv build/unit_tests build/firmware_v1.bin&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;CRYPTOGRAPHIC_SIGNATURE_OK&amp;quot; &amp;gt;&amp;gt; build/firmware_v1.bin&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Rules:&amp;#039;&amp;#039;&amp;#039; We ONLY want to release firmware automatically from the main branch! Add a &amp;lt;code&amp;gt;rules:&amp;lt;/code&amp;gt; section with &amp;lt;code&amp;gt;- if: &amp;#039;$CI_COMMIT_BRANCH == &amp;quot;main&amp;quot;&amp;#039;&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Artifacts:&amp;#039;&amp;#039;&amp;#039; Save &amp;lt;code&amp;gt;build/firmware_v1.bin&amp;lt;/code&amp;gt; as an artifact that never expires.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 4): On-Demand Push Deployment&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Sometimes we need to instantly push an update to a specific machine (e.g., a prototype in the lab) without waiting for it to poll. We will simulate an SSH deployment using pipeline variables. &lt;br /&gt;
&lt;br /&gt;
Add another job named &amp;lt;code&amp;gt;deploy_to_edge_device&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Pull from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Rules:&amp;#039;&amp;#039;&amp;#039; We want this to be an &amp;quot;On-Demand&amp;quot; job that requires a human to click a play button. Add a &amp;lt;code&amp;gt;rules:&amp;lt;/code&amp;gt; section with &amp;lt;code&amp;gt;- when: manual&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Simulate securely pushing the binary to a specific IP address using an environment variable (&amp;lt;code&amp;gt;$TARGET_IP&amp;lt;/code&amp;gt;):&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;Connecting to Edge Device at $TARGET_IP...&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;scp build/unit_tests admin@$TARGET_IP:/opt/smart-oven/bin/&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;Deployment to $TARGET_IP successful!&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Test the Deployments:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Push your code to &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. &lt;br /&gt;
# You will see the &amp;lt;code&amp;gt;release_ota_firmware&amp;lt;/code&amp;gt; job run automatically. &lt;br /&gt;
# The &amp;lt;code&amp;gt;deploy_to_edge_device&amp;lt;/code&amp;gt; job will be paused (marked with a &amp;quot;Play&amp;quot; icon). &lt;br /&gt;
# Click the Play icon, and GitLab will allow you to manually input a value for &amp;lt;code&amp;gt;TARGET_IP&amp;lt;/code&amp;gt; before executing the push!&lt;br /&gt;
&lt;br /&gt;
== Phase 6: Cleanup ==&lt;br /&gt;
To prevent your runner from polling GitLab forever and draining your laptop battery, gracefully shut it down and remove it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker stop my-local-runner&lt;br /&gt;
docker rm my-local-runner&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the GitLab UI, go back to Settings -&amp;gt; CI/CD -&amp;gt; Runners, and delete the offline runner.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Assignment Submission ===&lt;br /&gt;
Upload &amp;#039;&amp;#039;&amp;#039;ONLY&amp;#039;&amp;#039;&amp;#039; your finalized &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to the Moodle VPL assignment. The automated grading server will analyze your YAML syntax to ensure you correctly configured the stages, artifacts, custom runner routing, and deployment rules.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8327</id>
		<title>SDPT Lab 6</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8327"/>
		<updated>2026-04-19T17:05:52Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 6 Lab Activity: CI/CD Pipelines &amp;amp; Custom Runners =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
Today, we automate everything. You will transition from compiling code on your laptop to architecting a professional CI/CD pipeline. &lt;br /&gt;
&lt;br /&gt;
We will accomplish this in six phases:&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Repository Setup:&amp;#039;&amp;#039;&amp;#039; Migrating your code to GitLab.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Infrastructure:&amp;#039;&amp;#039;&amp;#039; Spinning up and registering your own local GitLab Runner via Docker.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Integration (Build):&amp;#039;&amp;#039;&amp;#039; Writing your first CI job and generating Artifacts.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Integration (Test):&amp;#039;&amp;#039;&amp;#039; Consuming Artifacts and testing via QEMU.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Continuous Deployment (CD):&amp;#039;&amp;#039;&amp;#039; Creating a simulated OTA firmware release restricted to the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cleanup:&amp;#039;&amp;#039;&amp;#039; Deregistering and destroying your local runner.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 1: Repository Setup ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Create a Project:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Log into GitLab and create a new blank project named &amp;lt;code&amp;gt;sdpt-smart-oven&amp;lt;/code&amp;gt;. Uncheck &amp;quot;Initialize repository with a README&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Push Your Code:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Open your terminal on your laptop, navigate to your Week 5 project folder, and push your code to this new repository.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git init&lt;br /&gt;
git branch -m main&lt;br /&gt;
git remote add origin https://gitlab.com/&amp;lt;your-username&amp;gt;/sdpt-smart-oven.git&lt;br /&gt;
git add .&lt;br /&gt;
git commit -m &amp;quot;Initial commit: Oven Controller with CMake and Docker&amp;quot;&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 2: Registering a Local Runner ==&lt;br /&gt;
GitLab provides shared runners, but embedded systems often require custom hardware or specific toolchains. We will host our own Runner!&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Get Your Registration Token:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
In your GitLab project, go to &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;CI/CD&amp;#039;&amp;#039;&amp;#039;. Expand the &amp;#039;&amp;#039;&amp;#039;Runners&amp;#039;&amp;#039;&amp;#039; section. Under &amp;quot;Project runners&amp;quot;, click &amp;quot;New project runner&amp;quot;. Add the tag &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt; and click Create. Copy the &amp;#039;&amp;#039;&amp;#039;registration token&amp;#039;&amp;#039;&amp;#039; it gives you.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Start the Runner via Docker:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
On your laptop terminal, run a background Docker container to act as your runner. (We mount the Docker socket so the runner can spawn its own containers!)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run -d --name my-local-runner --restart always -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;3. Register the Runner:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Now, execute the registration command inside the running container:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker exec -it my-local-runner gitlab-runner register&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;GitLab instance URL:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;https://gitlab.com/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Registration token:&amp;#039;&amp;#039;&amp;#039; (Paste your token from step 1)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Description:&amp;#039;&amp;#039;&amp;#039; My Laptop Runner&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tags:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Executor:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Default image:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;ubuntu:22.04&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Refresh your GitLab Runners page. You should see a green circle indicating your local runner is alive and listening for jobs!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 3: The Build Stage &amp;amp; Artifacts ==&lt;br /&gt;
We will now tell your Runner how to build our code. Create a file named exactly &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; in your project root.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 1):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Image:&amp;#039;&amp;#039;&amp;#039; Set &amp;lt;code&amp;gt;image:&amp;lt;/code&amp;gt; to the ARM Docker image you built last week.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Stages:&amp;#039;&amp;#039;&amp;#039; Define three stages: &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Build Job:&amp;#039;&amp;#039;&amp;#039; Create a job named &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Assign it to the &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
#* Use &amp;lt;code&amp;gt;tags: [local-embedded]&amp;lt;/code&amp;gt; to force this job to run on YOUR laptop&amp;#039;s runner.&lt;br /&gt;
#* In the &amp;lt;code&amp;gt;script&amp;lt;/code&amp;gt;, run CMake for &amp;lt;code&amp;gt;aarch64&amp;lt;/code&amp;gt; and run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Create &amp;lt;code&amp;gt;artifacts&amp;lt;/code&amp;gt; to save the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory (expire in 1 hour).&lt;br /&gt;
&lt;br /&gt;
Commit and push. Watch the pipeline in GitLab. Your laptop&amp;#039;s fan might spin up because *your* Docker daemon is doing the heavy lifting!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 4: The Test Stage &amp;amp; Merge Checks ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 2):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Add a job named &amp;lt;code&amp;gt;verify_logic&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Require the artifacts from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Navigate to &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; and execute tests using QEMU (&amp;lt;code&amp;gt;qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Test the Block:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Go to GitLab &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Merge Requests&amp;#039;&amp;#039;&amp;#039; -&amp;gt; Check &amp;quot;Pipelines must succeed&amp;quot;.&lt;br /&gt;
# Create a new branch: &amp;lt;code&amp;gt;git checkout -b feature/broken-math&amp;lt;/code&amp;gt;&lt;br /&gt;
# Break an assertion in your C++ tests and push the branch.&lt;br /&gt;
# Open a Merge Request. Watch the test stage fail and observe the Merge button physically lock you out! Fix the code, push again, and Merge it.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 5: Continuous Deployment (CD) ==&lt;br /&gt;
Once the code hits the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch, we want to automatically package it for an Over-The-Air (OTA) firmware update.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge (Part 3):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Add a final job named &amp;lt;code&amp;gt;release_ota_firmware&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Stage: &amp;lt;code&amp;gt;deploy&amp;lt;/code&amp;gt;&lt;br /&gt;
# Tags: &amp;lt;code&amp;gt;local-embedded&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; Pull from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;script:&amp;lt;/code&amp;gt; Rename your binary to a release format and simulate cryptographically signing it:&lt;br /&gt;
#* &amp;lt;code&amp;gt;mv build/unit_tests build/firmware_v1.bin&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;echo &amp;quot;CRYPTOGRAPHIC_SIGNATURE_OK&amp;quot; &amp;gt;&amp;gt; build/firmware_v1.bin&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Rules:&amp;#039;&amp;#039;&amp;#039; We ONLY want to release firmware from the main branch! Add a &amp;lt;code&amp;gt;rules:&amp;lt;/code&amp;gt; section with &amp;lt;code&amp;gt;- if: &amp;#039;$CI_COMMIT_BRANCH == &amp;quot;main&amp;quot;&amp;#039;&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Artifacts:&amp;#039;&amp;#039;&amp;#039; Save &amp;lt;code&amp;gt;build/firmware_v1.bin&amp;lt;/code&amp;gt; as an artifact that never expires.&lt;br /&gt;
&lt;br /&gt;
Push to main. You should see a 3-stage pipeline complete successfully. You can now download your final &amp;quot;signed&amp;quot; firmware directly from the GitLab UI!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 6: Cleanup ==&lt;br /&gt;
To prevent your runner from polling GitLab forever and draining your laptop battery, gracefully shut it down and remove it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker stop my-local-runner&lt;br /&gt;
docker rm my-local-runner&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the GitLab UI, go back to Settings -&amp;gt; CI/CD -&amp;gt; Runners, and delete the offline runner.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Assignment Submission ===&lt;br /&gt;
Upload &amp;#039;&amp;#039;&amp;#039;ONLY&amp;#039;&amp;#039;&amp;#039; your finalized &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to the Moodle VPL assignment. The automated grading server will analyze your YAML syntax to ensure you correctly configured the stages, artifacts, custom runner routing, and deployment rules.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8326</id>
		<title>SDPT Lab 6</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_6&amp;diff=8326"/>
		<updated>2026-04-19T17:03:02Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: = Week 6 Lab Activity: Continuous Integration (CI) with GitLab =  == Objective == Today, we automate everything. You will transition from compiling code on your laptop to architect...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 6 Lab Activity: Continuous Integration (CI) with GitLab =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
Today, we automate everything. You will transition from compiling code on your laptop to architecting a professional CI pipeline. You will use your Docker image from last week to cross-compile your C++ code, run your Google Tests in QEMU, and configure GitLab to mechanically prevent broken code from ever reaching the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch.&lt;br /&gt;
&lt;br /&gt;
We will accomplish this in four phases:&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Repository Setup:&amp;#039;&amp;#039;&amp;#039; Migrating your code to GitLab.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Build Stage:&amp;#039;&amp;#039;&amp;#039; Writing your first CI job and generating Artifacts.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Test Stage:&amp;#039;&amp;#039;&amp;#039; Consuming Artifacts and failing the pipeline on bad tests.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Merge Checks:&amp;#039;&amp;#039;&amp;#039; Enforcing quality control via Merge Requests.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 1: Repository Setup ==&lt;br /&gt;
To use GitLab CI, your code must live on a GitLab server.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Create a Project:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Log into GitLab and create a new blank project named &amp;lt;code&amp;gt;sdpt-smart-oven&amp;lt;/code&amp;gt;. Uncheck &amp;quot;Initialize repository with a README&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Push Your Code:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Open your terminal on your laptop, navigate to your Week 5 project folder, and push your code to this new repository.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git init&lt;br /&gt;
git branch -m main&lt;br /&gt;
git remote add origin https://gitlab.com/&amp;lt;your-username&amp;gt;/sdpt-smart-oven.git&lt;br /&gt;
git add .&lt;br /&gt;
git commit -m &amp;quot;Initial commit: Oven Controller with CMake and Docker&amp;quot;&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 2: The Build Stage &amp;amp; Artifacts ==&lt;br /&gt;
We will now tell the GitLab Runner how to build our code using the Docker image you designed last week.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Create a file named exactly &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; in the root of your project. Write the YAML to meet these specifications:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Image:&amp;#039;&amp;#039;&amp;#039; Set the global &amp;lt;code&amp;gt;image:&amp;lt;/code&amp;gt; to the Docker registry URL of the ARM image you built in Week 5 (or use a public equivalent provided by the instructor, e.g., &amp;lt;code&amp;gt;registry.gitlab.com/sdpt-course/arm-build-env:latest&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Stages:&amp;#039;&amp;#039;&amp;#039; Define two stages: &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Build Job:&amp;#039;&amp;#039;&amp;#039; Create a job named &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Assign it to the &amp;lt;code&amp;gt;build&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
#* In the &amp;lt;code&amp;gt;script&amp;lt;/code&amp;gt; section, create a build folder, run CMake for the &amp;lt;code&amp;gt;aarch64&amp;lt;/code&amp;gt; compiler, and run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Artifacts:&amp;#039;&amp;#039;&amp;#039; Tell GitLab to save the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory as an artifact that expires in 1 hour. (If you forget this, your compiled binary will be deleted before the test stage starts!)&lt;br /&gt;
&lt;br /&gt;
Commit and push this file. Go to your GitLab project -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Build&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Pipelines&amp;#039;&amp;#039;&amp;#039;. You should see your pipeline running! Click on it to watch the live terminal output of the GitLab Runner.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 3: The Test Stage ==&lt;br /&gt;
Once your build job turns green, it&amp;#039;s time to test the artifact.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Update your YAML:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Add a second job named &amp;lt;code&amp;gt;verify_logic&amp;lt;/code&amp;gt; to your &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt;:&lt;br /&gt;
# Assign it to the &amp;lt;code&amp;gt;test&amp;lt;/code&amp;gt; stage.&lt;br /&gt;
# Use the &amp;lt;code&amp;gt;dependencies:&amp;lt;/code&amp;gt; keyword to explicitly require the artifacts from &amp;lt;code&amp;gt;compile_firmware&amp;lt;/code&amp;gt;.&lt;br /&gt;
# In the &amp;lt;code&amp;gt;script&amp;lt;/code&amp;gt; section, navigate to the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory and execute your tests using QEMU (&amp;lt;code&amp;gt;qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Push the updated YAML. Watch the pipeline. The Runner will download the compiled binary from the previous stage and execute your tests!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 4: Merge Checks and Failure (The DevOps Climax) ==&lt;br /&gt;
A pipeline is useless if developers can just bypass it. We will now configure GitLab to block bad code.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Protect the Main Branch:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
In GitLab, go to &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Merge Requests&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
Scroll down to &amp;#039;&amp;#039;&amp;#039;Merge checks&amp;#039;&amp;#039;&amp;#039; and check the box that says: &amp;#039;&amp;#039;&amp;quot;Pipelines must succeed&amp;quot;&amp;#039;&amp;#039;. Save changes.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Create a Feature Branch:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Back on your laptop terminal, create a new branch:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout -b feature/broken-sensor&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;3. Sabotage the Code!&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Open your &amp;lt;code&amp;gt;test_oven.cpp&amp;lt;/code&amp;gt; file. Intentionally change a mathematical assertion so that it will fail (e.g., change &amp;lt;code&amp;gt;EXPECT_EQ(temp, 100);&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;EXPECT_EQ(temp, 999);&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;4. Push and Open a Merge Request:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Commit your broken test and push the branch to GitLab. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git commit -am &amp;quot;feat: updated sensor logic (with bugs)&amp;quot;&lt;br /&gt;
git push -u origin feature/broken-sensor&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In GitLab, open a &amp;#039;&amp;#039;&amp;#039;Merge Request&amp;#039;&amp;#039;&amp;#039; from your feature branch into &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;5. Observe the Block:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Wait for the pipeline to run. The Build stage will pass, but the Test stage will turn RED because Google Test caught your broken math. &lt;br /&gt;
Look at the Merge Request page. &amp;#039;&amp;#039;&amp;#039;The Merge button is physically disabled!&amp;#039;&amp;#039;&amp;#039; GitLab has successfully protected your production code from human error.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;6. Fix and Merge:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Fix the test on your laptop, commit, and push again. The pipeline will automatically re-run, turn green, and unlock the Merge button. Click Merge!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Assignment Submission ===&lt;br /&gt;
Upload &amp;#039;&amp;#039;&amp;#039;ONLY&amp;#039;&amp;#039;&amp;#039; your finalized &amp;lt;code&amp;gt;.gitlab-ci.yml&amp;lt;/code&amp;gt; to the Moodle VPL assignment. The automated grading server will analyze your YAML syntax to ensure you correctly configured the stages, artifacts, and QEMU execution.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8325</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8325"/>
		<updated>2026-04-19T17:02:55Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;br /&gt;
* [[SDPT Lab 2]]&lt;br /&gt;
* [[SDPT Lab 3]]&lt;br /&gt;
* [[SDPT Lab 4]]&lt;br /&gt;
* [[SDPT Lab 5]]&lt;br /&gt;
* [[SDPT Lab 6]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_5&amp;diff=8317</id>
		<title>SDPT Lab 5</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_5&amp;diff=8317"/>
		<updated>2026-03-30T13:55:46Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 5 Lab Activity: Containerization &amp;amp; Cross-Compilation =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
This week, we eliminate the &amp;quot;It works on my machine&amp;quot; problem. You will learn how to build isolated Linux environments, cross-compile your &amp;lt;code&amp;gt;OvenController&amp;lt;/code&amp;gt; C++ code for an ARM architecture, and solve the complex problem of linking third-party static and dynamic libraries compiled for foreign architectures.&lt;br /&gt;
&lt;br /&gt;
We will accomplish this in three phases:&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Preparing CMake:&amp;#039;&amp;#039;&amp;#039; Updating the build system to link an external database library.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Manual Container (The &amp;quot;Old Way&amp;quot;):&amp;#039;&amp;#039;&amp;#039; Building the cross-compilation environment by hand to understand the underlying mechanics.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Infrastructure as Code (The &amp;quot;Modern Way&amp;quot;):&amp;#039;&amp;#039;&amp;#039; Automating the entire environment with a &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 1: Preparing CMake for Foreign Libraries ==&lt;br /&gt;
Imagine our &amp;lt;code&amp;gt;OvenController&amp;lt;/code&amp;gt; needs to log telemetry data locally using an SQLite database. To do this, we need to link the &amp;lt;code&amp;gt;sqlite3&amp;lt;/code&amp;gt; library. &lt;br /&gt;
&lt;br /&gt;
Open your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; from Week 4 and add the standard linking commands. &amp;#039;&amp;#039;(Note: CMake is smart enough to look for the correct architecture version of this library based on the compiler we provide later).&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cmake&amp;quot;&amp;gt;&lt;br /&gt;
# Add this near the bottom of your CMakeLists.txt&lt;br /&gt;
find_package(PkgConfig REQUIRED)&lt;br /&gt;
pkg_check_modules(SQLITE3 REQUIRED sqlite3)&lt;br /&gt;
&lt;br /&gt;
# Add the includes and link the library to your executable&lt;br /&gt;
target_include_directories(unit_tests PRIVATE ${SQLITE3_INCLUDE_DIRS})&lt;br /&gt;
target_link_libraries(unit_tests PRIVATE ${SQLITE3_LIBRARIES})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 2: The Manual Container (The &amp;quot;Old Way&amp;quot;) ==&lt;br /&gt;
Before we automate, let&amp;#039;s understand what Docker is actually doing under the hood.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Start a raw, interactive Ubuntu container:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Open your terminal and run a fresh Ubuntu 22.04 image, mounting your current code directory into &amp;lt;code&amp;gt;/app&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run -it --name manual-build-env -v ${PWD}:/app ubuntu:22.04 /bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Notice your terminal prompt has changed. You are now the root user inside an isolated Linux environment.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. The &amp;quot;Multiarch&amp;quot; Superpower:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
If we just run &amp;lt;code&amp;gt;apt-get install libsqlite3-dev&amp;lt;/code&amp;gt;, Ubuntu will download the &amp;lt;code&amp;gt;x86_64&amp;lt;/code&amp;gt; version. If we try to cross-compile our ARM code against it, the linker will violently crash. We must explicitly tell Ubuntu&amp;#039;s package manager to accept packages for a foreign architecture (&amp;lt;code&amp;gt;arm64&amp;lt;/code&amp;gt;).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
dpkg --add-architecture arm64&lt;br /&gt;
apt-get update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;3. Install the Toolchain and Foreign Libraries:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Now we install our cross-compiler, QEMU emulator, and the specifically compiled &amp;#039;&amp;#039;&amp;#039;ARM version&amp;#039;&amp;#039;&amp;#039; of our library (&amp;lt;code&amp;gt;:arm64&amp;lt;/code&amp;gt;).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt-get install -y build-essential cmake pkg-config g++-aarch64-linux-gnu qemu-user qemu-user-static&lt;br /&gt;
apt-get install -y libsqlite3-dev:arm64&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;4. Cross-Compile and Emulate:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Navigate to your mounted code and build the project for ARM. We use a command-line flag to tell CMake to use the ARM compiler instead of native GCC.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /app&lt;br /&gt;
mkdir build_arm &amp;amp;&amp;amp; cd build_arm&lt;br /&gt;
cmake -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ ..&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you try to run &amp;lt;code&amp;gt;./unit_tests&amp;lt;/code&amp;gt; natively, Linux will throw an &amp;lt;code&amp;gt;Exec format error&amp;lt;/code&amp;gt;. Use QEMU to emulate the execution of your ARM binary. Because we linked a dynamic library, we must tell QEMU where to find the ARM shared objects (&amp;lt;code&amp;gt;-L&amp;lt;/code&amp;gt; flag):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Verify that your Google Tests pass on the emulated architecture!&amp;#039;&amp;#039; Type &amp;lt;code&amp;gt;exit&amp;lt;/code&amp;gt; to leave and stop the container.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 3: Infrastructure as Code (The &amp;quot;Modern Way&amp;quot;) ==&lt;br /&gt;
Manually typing &amp;lt;code&amp;gt;apt-get&amp;lt;/code&amp;gt; commands, enabling architectures, and committing containers is tedious and error-prone. Modern DevOps engineers automate this using a &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Challenge:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Create a file named exactly &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; (no extension) in your project root. Translate the manual steps you just took into an automated recipe that meets the following strict specifications:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Base Image:&amp;#039;&amp;#039;&amp;#039; Must use &amp;lt;code&amp;gt;ubuntu:22.04&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Environment:&amp;#039;&amp;#039;&amp;#039; Set &amp;lt;code&amp;gt;DEBIAN_FRONTEND&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;noninteractive&amp;lt;/code&amp;gt; to prevent the build from hanging on timezone prompts.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Architecture:&amp;#039;&amp;#039;&amp;#039; Use a &amp;lt;code&amp;gt;RUN&amp;lt;/code&amp;gt; command to add the &amp;lt;code&amp;gt;arm64&amp;lt;/code&amp;gt; architecture to &amp;lt;code&amp;gt;dpkg&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Mega-Layer:&amp;#039;&amp;#039;&amp;#039; Use a single &amp;lt;code&amp;gt;RUN&amp;lt;/code&amp;gt; command to update &amp;lt;code&amp;gt;apt-get&amp;lt;/code&amp;gt;, install all required tools (&amp;lt;code&amp;gt;build-essential cmake pkg-config g++-aarch64-linux-gnu qemu-user qemu-user-static libsqlite3-dev:arm64&amp;lt;/code&amp;gt;), and immediately clean up the apt cache (&amp;lt;code&amp;gt;rm -rf /var/lib/apt/lists/*&amp;lt;/code&amp;gt;) to keep the image size small. &amp;#039;&amp;#039;(Hint: Chain your commands with &amp;lt;code&amp;gt;&amp;amp;&amp;amp;&amp;lt;/code&amp;gt; and use &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt; for multi-line formatting).&amp;#039;&amp;#039;&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Workspace:&amp;#039;&amp;#039;&amp;#039; Set the working directory inside the container to &amp;lt;code&amp;gt;/app&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;PID 1:&amp;#039;&amp;#039;&amp;#039; Set the default command (&amp;lt;code&amp;gt;CMD&amp;lt;/code&amp;gt;) to launch &amp;lt;code&amp;gt;/bin/bash&amp;lt;/code&amp;gt; so the container stays alive interactively.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Build and Test Your Image:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Once you have written your Dockerfile, test your infrastructure code by building and running it. It should behave exactly like your manual container did:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker build -t automated-arm-env:latest .&lt;br /&gt;
docker run -it --rm -v ${PWD}:/app automated-arm-env:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Assignment Submission ===&lt;br /&gt;
Upload &amp;#039;&amp;#039;&amp;#039;ONLY&amp;#039;&amp;#039;&amp;#039; your &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; to the Moodle VPL assignment. The automated grading server will run static analysis on your infrastructure-as-code syntax to verify your architecture setup, toolchain requirements, and layer optimization.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_5&amp;diff=8316</id>
		<title>SDPT Lab 5</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_5&amp;diff=8316"/>
		<updated>2026-03-30T13:52:27Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Week 5 Lab Activity: Containerization &amp;amp; Cross-Compilation =&lt;br /&gt;
&lt;br /&gt;
== Objective ==&lt;br /&gt;
This week, we eliminate the &amp;quot;It works on my machine&amp;quot; problem. You will learn how to build isolated Linux environments, cross-compile your &amp;lt;code&amp;gt;OvenController&amp;lt;/code&amp;gt; C++ code for an ARM architecture, and solve the complex problem of linking third-party static and dynamic libraries compiled for foreign architectures.&lt;br /&gt;
&lt;br /&gt;
We will accomplish this in three phases:&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Preparing CMake:&amp;#039;&amp;#039;&amp;#039; Updating the build system to link an external database library.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The Manual Container (The &amp;quot;Old Way&amp;quot;):&amp;#039;&amp;#039;&amp;#039; Building the cross-compilation environment by hand to understand the underlying mechanics.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Infrastructure as Code (The &amp;quot;Modern Way&amp;quot;):&amp;#039;&amp;#039;&amp;#039; Automating the entire environment with a &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 1: Preparing CMake for Foreign Libraries ==&lt;br /&gt;
Imagine our &amp;lt;code&amp;gt;OvenController&amp;lt;/code&amp;gt; needs to log telemetry data locally using an SQLite database. To do this, we need to link the &amp;lt;code&amp;gt;sqlite3&amp;lt;/code&amp;gt; library. &lt;br /&gt;
&lt;br /&gt;
Open your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; from Week 4 and add the standard linking commands. &amp;#039;&amp;#039;(Note: CMake is smart enough to look for the correct architecture version of this library based on the compiler we provide later).&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cmake&amp;quot;&amp;gt;&lt;br /&gt;
# Add this near the bottom of your CMakeLists.txt&lt;br /&gt;
find_package(PkgConfig REQUIRED)&lt;br /&gt;
pkg_check_modules(SQLITE3 REQUIRED sqlite3)&lt;br /&gt;
&lt;br /&gt;
# Add the includes and link the library to your executable&lt;br /&gt;
target_include_directories(unit_tests PRIVATE ${SQLITE3_INCLUDE_DIRS})&lt;br /&gt;
target_link_libraries(unit_tests PRIVATE ${SQLITE3_LIBRARIES})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 2: The Manual Container (The &amp;quot;Old Way&amp;quot;) ==&lt;br /&gt;
Before we automate, let&amp;#039;s understand what Docker is actually doing under the hood.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Start a raw, interactive Ubuntu container:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Open your terminal and run a fresh Ubuntu 22.04 image, mounting your current code directory into &amp;lt;code&amp;gt;/app&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run -it --name manual-build-env -v ${PWD}:/app ubuntu:22.04 /bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Notice your terminal prompt has changed. You are now the root user inside an isolated Linux environment.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. The &amp;quot;Multiarch&amp;quot; Superpower:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
If we just run &amp;lt;code&amp;gt;apt-get install libsqlite3-dev&amp;lt;/code&amp;gt;, Ubuntu will download the &amp;lt;code&amp;gt;x86_64&amp;lt;/code&amp;gt; version. If we try to cross-compile our ARM code against it, the linker will violently crash. We must explicitly tell Ubuntu&amp;#039;s package manager to accept packages for a foreign architecture (&amp;lt;code&amp;gt;arm64&amp;lt;/code&amp;gt;).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
dpkg --add-architecture arm64&lt;br /&gt;
apt-get update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;3. Install the Toolchain and Foreign Libraries:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Now we install our cross-compiler, QEMU emulator, and the specifically compiled &amp;#039;&amp;#039;&amp;#039;ARM version&amp;#039;&amp;#039;&amp;#039; of our library (&amp;lt;code&amp;gt;:arm64&amp;lt;/code&amp;gt;).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt-get install -y build-essential cmake pkg-config g++-aarch64-linux-gnu qemu-user qemu-user-static&lt;br /&gt;
apt-get install -y libsqlite3-dev:arm64&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;4. Cross-Compile and Emulate:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Navigate to your mounted code and build the project for ARM. We use a command-line flag to tell CMake to use the ARM compiler instead of native GCC.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /app&lt;br /&gt;
mkdir build_arm &amp;amp;&amp;amp; cd build_arm&lt;br /&gt;
cmake -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ ..&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you try to run &amp;lt;code&amp;gt;./unit_tests&amp;lt;/code&amp;gt; natively, Linux will throw an &amp;lt;code&amp;gt;Exec format error&amp;lt;/code&amp;gt;. Use QEMU to emulate the execution of your ARM binary. Because we linked a dynamic library, we must tell QEMU where to find the ARM shared objects (&amp;lt;code&amp;gt;-L&amp;lt;/code&amp;gt; flag):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Verify that your Google Tests pass on the emulated architecture!&amp;#039;&amp;#039; Type &amp;lt;code&amp;gt;exit&amp;lt;/code&amp;gt; to leave and stop the container.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Phase 3: Infrastructure as Code (The &amp;quot;Modern Way&amp;quot;) ==&lt;br /&gt;
Manually typing &amp;lt;code&amp;gt;apt-get&amp;lt;/code&amp;gt; commands, enabling architectures, and committing containers is tedious and error-prone. Modern DevOps engineers automate this using a &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Write the Dockerfile:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Create a file named exactly &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; (no extension) in your project root. Translate the manual steps you just took into an automated recipe.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;dockerfile&amp;quot;&amp;gt;&lt;br /&gt;
# 1. Base Image&lt;br /&gt;
FROM ubuntu:22.04&lt;br /&gt;
&lt;br /&gt;
# 2. Prevent interactive timezone prompts&lt;br /&gt;
ENV DEBIAN_FRONTEND=noninteractive&lt;br /&gt;
&lt;br /&gt;
# 3. Enable ARM64 Architecture for foreign libraries&lt;br /&gt;
RUN dpkg --add-architecture arm64&lt;br /&gt;
&lt;br /&gt;
# 4. Install toolchain &amp;amp; ARM libraries in ONE layer to save space&lt;br /&gt;
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \&lt;br /&gt;
    build-essential \&lt;br /&gt;
    cmake \&lt;br /&gt;
    pkg-config \&lt;br /&gt;
    g++-aarch64-linux-gnu \&lt;br /&gt;
    qemu-user \&lt;br /&gt;
    qemu-user-static \&lt;br /&gt;
    libsqlite3-dev:arm64 \&lt;br /&gt;
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;br /&gt;
&lt;br /&gt;
# 5. Set Workspace&lt;br /&gt;
WORKDIR /app&lt;br /&gt;
&lt;br /&gt;
# 6. Keep the container alive interactively&lt;br /&gt;
CMD [&amp;quot;/bin/bash&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2. Build the Automated Image:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Ask Docker Engine to read your recipe and build the image from scratch.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker build -t automated-arm-env:latest .&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;3. Run your Final Environment:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run -it --rm -v ${PWD}:/app automated-arm-env:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You now have a perfectly reproducible, portable embedded toolchain that natively resolves third-party ARM dependencies. &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Assignment Submission ===&lt;br /&gt;
Upload &amp;#039;&amp;#039;&amp;#039;ONLY&amp;#039;&amp;#039;&amp;#039; your &amp;lt;code&amp;gt;Dockerfile&amp;lt;/code&amp;gt; to the Moodle VPL assignment. The automated grading server will run static analysis on your infrastructure-as-code syntax to verify your architecture setup, toolchain requirements, and layer optimization.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_5&amp;diff=8315</id>
		<title>SDPT Lab 5</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_5&amp;diff=8315"/>
		<updated>2026-03-30T13:49:46Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: # Week 5 Lab Activity: Containerization &amp;amp; Cross-Compilation  ## Objective This week, we eliminate the &amp;quot;It works on my machine&amp;quot; problem. You will learn how to build isolated Linux e...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Week 5 Lab Activity: Containerization &amp;amp; Cross-Compilation&lt;br /&gt;
&lt;br /&gt;
## Objective&lt;br /&gt;
This week, we eliminate the &amp;quot;It works on my machine&amp;quot; problem. You will learn how to build isolated Linux environments, cross-compile your `OvenController` C++ code for an ARM architecture, and solve the complex problem of linking third-party static and dynamic libraries compiled for foreign architectures.&lt;br /&gt;
&lt;br /&gt;
We will accomplish this in three phases:&lt;br /&gt;
1. **Preparing CMake:** Updating the build system to link an external database library.&lt;br /&gt;
2. **The Manual Container (The &amp;quot;Old Way&amp;quot;):** Building the cross-compilation environment by hand to understand the underlying mechanics.&lt;br /&gt;
3. **Infrastructure as Code (The &amp;quot;Modern Way&amp;quot;):** Automating the entire environment with a `Dockerfile`.&lt;br /&gt;
&lt;br /&gt;
## Phase 1: Preparing CMake for Foreign Libraries&lt;br /&gt;
Imagine our `OvenController` needs to log telemetry data locally using an SQLite database. To do this, we need to link the `sqlite3` library. &lt;br /&gt;
&lt;br /&gt;
Open your `CMakeLists.txt` from Week 4 and add the standard linking commands. *(Note: CMake is smart enough to look for the correct architecture version of this library based on the compiler we provide later).*&lt;br /&gt;
&lt;br /&gt;
```cmake&lt;br /&gt;
# Add this near the bottom of your CMakeLists.txt&lt;br /&gt;
find_package(PkgConfig REQUIRED)&lt;br /&gt;
pkg_check_modules(SQLITE3 REQUIRED sqlite3)&lt;br /&gt;
&lt;br /&gt;
# Add the includes and link the library to your executable&lt;br /&gt;
target_include_directories(unit_tests PRIVATE ${SQLITE3_INCLUDE_DIRS})&lt;br /&gt;
target_link_libraries(unit_tests PRIVATE ${SQLITE3_LIBRARIES})&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Phase 2: The Manual Container (The &amp;quot;Old Way&amp;quot;)&lt;br /&gt;
Before we automate, let&amp;#039;s understand what Docker is actually doing under the hood.&lt;br /&gt;
&lt;br /&gt;
**1. Start a raw, interactive Ubuntu container:**&lt;br /&gt;
Open your terminal and run a fresh Ubuntu 22.04 image, mounting your current code directory into `/app`:&lt;br /&gt;
```bash&lt;br /&gt;
docker run -it --name manual-build-env -v ${PWD}:/app ubuntu:22.04 /bin/bash&lt;br /&gt;
```&lt;br /&gt;
*Notice your terminal prompt has changed. You are now the `root` user inside an isolated Linux environment.*&lt;br /&gt;
&lt;br /&gt;
**2. The &amp;quot;Multiarch&amp;quot; Superpower:**&lt;br /&gt;
If we just run `apt-get install libsqlite3-dev`, Ubuntu will download the `x86_64` version. If we try to cross-compile our ARM code against it, the linker will violently crash. We must explicitly tell Ubuntu&amp;#039;s package manager to accept packages for a foreign architecture (`arm64`).&lt;br /&gt;
```bash&lt;br /&gt;
dpkg --add-architecture arm64&lt;br /&gt;
apt-get update&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**3. Install the Toolchain and Foreign Libraries:**&lt;br /&gt;
Now we install our cross-compiler, QEMU emulator, and the specifically compiled **ARM version** of our library (`:arm64`).&lt;br /&gt;
```bash&lt;br /&gt;
apt-get install -y build-essential cmake pkg-config g++-aarch64-linux-gnu qemu-user qemu-user-static&lt;br /&gt;
apt-get install -y libsqlite3-dev:arm64&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**4. Cross-Compile and Emulate:**&lt;br /&gt;
Navigate to your mounted code and build the project for ARM. We use a command-line flag to tell CMake to use the ARM compiler instead of native GCC.&lt;br /&gt;
```bash&lt;br /&gt;
cd /app&lt;br /&gt;
mkdir build_arm &amp;amp;&amp;amp; cd build_arm&lt;br /&gt;
cmake -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ ..&lt;br /&gt;
make&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
If you try to run `./unit_tests` natively, Linux will throw an `Exec format error`. Use QEMU to emulate the execution of your ARM binary. Because we linked a dynamic library, we must tell QEMU where to find the ARM shared objects (`-L` flag):&lt;br /&gt;
```bash&lt;br /&gt;
qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests&lt;br /&gt;
```&lt;br /&gt;
*Verify that your Google Tests pass on the emulated architecture!* Type `exit` to leave and stop the container.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## Phase 3: Infrastructure as Code (The &amp;quot;Modern Way&amp;quot;)&lt;br /&gt;
Manually typing `apt-get` commands, enabling architectures, and committing containers is tedious and error-prone. Modern DevOps engineers automate this using a `Dockerfile`.&lt;br /&gt;
&lt;br /&gt;
**1. Write the Dockerfile:**&lt;br /&gt;
Create a file named exactly `Dockerfile` (no extension) in your project root. Translate the manual steps you just took into an automated recipe.&lt;br /&gt;
&lt;br /&gt;
```dockerfile&lt;br /&gt;
# 1. Base Image&lt;br /&gt;
FROM ubuntu:22.04&lt;br /&gt;
&lt;br /&gt;
# 2. Prevent interactive timezone prompts&lt;br /&gt;
ENV DEBIAN_FRONTEND=noninteractive&lt;br /&gt;
&lt;br /&gt;
# 3. Enable ARM64 Architecture for foreign libraries&lt;br /&gt;
RUN dpkg --add-architecture arm64&lt;br /&gt;
&lt;br /&gt;
# 4. Install toolchain &amp;amp; ARM libraries in ONE layer to save space&lt;br /&gt;
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \&lt;br /&gt;
    build-essential \&lt;br /&gt;
    cmake \&lt;br /&gt;
    pkg-config \&lt;br /&gt;
    g++-aarch64-linux-gnu \&lt;br /&gt;
    qemu-user \&lt;br /&gt;
    qemu-user-static \&lt;br /&gt;
    libsqlite3-dev:arm64 \&lt;br /&gt;
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;br /&gt;
&lt;br /&gt;
# 5. Set Workspace&lt;br /&gt;
WORKDIR /app&lt;br /&gt;
&lt;br /&gt;
# 6. Keep the container alive interactively&lt;br /&gt;
CMD [&amp;quot;/bin/bash&amp;quot;]&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**2. Build the Automated Image:**&lt;br /&gt;
Ask Docker Engine to read your recipe and build the image from scratch.&lt;br /&gt;
```bash&lt;br /&gt;
docker build -t automated-arm-env:latest .&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**3. Run your Final Environment:**&lt;br /&gt;
```bash&lt;br /&gt;
docker run -it --rm -v ${PWD}:/app automated-arm-env:latest&lt;br /&gt;
```&lt;br /&gt;
You now have a perfectly reproducible, portable embedded toolchain that natively resolves third-party ARM dependencies. &lt;br /&gt;
&lt;br /&gt;
### Assignment Submission&lt;br /&gt;
Upload **ONLY** your `Dockerfile` to the Moodle VPL assignment. The automated grading server will run static analysis on your infrastructure-as-code syntax to verify your architecture setup, toolchain requirements, and layer optimization.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8314</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8314"/>
		<updated>2026-03-30T13:47:36Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;br /&gt;
* [[SDPT Lab 2]]&lt;br /&gt;
* [[SDPT Lab 3]]&lt;br /&gt;
* [[SDPT Lab 4]]&lt;br /&gt;
* [[SDPT Lab 5]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_4&amp;diff=8299</id>
		<title>SDPT Lab 4</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_4&amp;diff=8299"/>
		<updated>2026-03-23T13:32:44Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 4: Software Verification - TDD, Mocking, and Code Coverage =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
In traditional embedded systems, testing involves compiling code, flashing it to a board, and physically observing the hardware. This is slow, expensive, and scales poorly. Today, we implement &amp;quot;Shift-Left Testing.&amp;quot; We will verify our C++ logic on our Host PC using automated frameworks before it ever touches a microcontroller.&lt;br /&gt;
&lt;br /&gt;
=== Goals ===&lt;br /&gt;
* Integrate Google Test and Google Mock via CMake.&lt;br /&gt;
* Write Unit Tests using the AAA (Arrange, Act, Assert) pattern.&lt;br /&gt;
* Use Dependency Injection to decouple business logic from hardware registers.&lt;br /&gt;
* Simulate hardware interactions using Google Mock (GMock).&lt;br /&gt;
* Generate interactive HTML Code Coverage reports using &amp;lt;code&amp;gt;gcovr&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Part 1: Theoretical Reference ==&lt;br /&gt;
&amp;#039;&amp;#039;Use this section as a reference manual to complete the challenges in Part 2.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Google Test &amp;amp; Mock Cheat Sheet ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Basic Assertions:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;lt;code&amp;gt;EXPECT_EQ(actual, expected);&amp;lt;/code&amp;gt; (Non-fatal equality check)&lt;br /&gt;
* &amp;lt;code&amp;gt;EXPECT_FLOAT_EQ(actual, expected);&amp;lt;/code&amp;gt; (Safe float comparison)&lt;br /&gt;
* &amp;lt;code&amp;gt;EXPECT_TRUE(condition);&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Mocking an Interface (GMock):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class MockSensor : public ISensor {&lt;br /&gt;
public:&lt;br /&gt;
    // MOCK_METHOD(ReturnType, MethodName, (Arguments), (override));&lt;br /&gt;
    MOCK_METHOD(float, read_temperature, (), (override));&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Setting Mock Expectations:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MockSensor fake_sensor;&lt;br /&gt;
// Program the mock to return 45.0 exactly twice.&lt;br /&gt;
EXPECT_CALL(fake_sensor, read_temperature())&lt;br /&gt;
    .Times(2)&lt;br /&gt;
    .WillRepeatedly(testing::Return(45.0f));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 CMake Debug &amp;amp; Coverage Setup ===&lt;br /&gt;
Coverage mathematically requires a completely unoptimized binary mapping exactly to your source code lines.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(CMAKE_BUILD_TYPE STREQUAL &amp;quot;Debug&amp;quot;)&lt;br /&gt;
    target_compile_options(my_target PRIVATE -O0 -g --coverage)&lt;br /&gt;
    target_link_options(my_target PRIVATE --coverage)&lt;br /&gt;
endif()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Running gcovr ===&lt;br /&gt;
Execute this from inside your &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory after running the tests:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
gcovr -r ../ . --html --html-details -o coverage.html -e &amp;quot;.*_deps.*&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Official Documentation &amp;amp; Tutorials ===&lt;br /&gt;
When you get stuck on syntax or advanced features during the lab, refer to these official resources:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Google Test:&amp;#039;&amp;#039;&amp;#039; [https://google.github.io/googletest/primer.html Googletest Primer (Official Tutorial)]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Google Mock:&amp;#039;&amp;#039;&amp;#039; [https://google.github.io/googletest/gmock_for_dummies.html gMock for Dummies] and the [https://google.github.io/googletest/reference/mocking.html Mocking Reference]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CMake FetchContent:&amp;#039;&amp;#039;&amp;#039; [https://cmake.org/cmake/help/latest/module/FetchContent.html Official CMake FetchContent Documentation]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Code Coverage (gcovr):&amp;#039;&amp;#039;&amp;#039; [https://gcovr.com/en/stable/guide.html gcovr User Guide]&lt;br /&gt;
&lt;br /&gt;
== Part 2: The Challenges ==&lt;br /&gt;
&lt;br /&gt;
=== Setup: The Raw Materials ===&lt;br /&gt;
You are building the safety controller for an industrial oven. It must read temperatures from an I2C sensor and trigger a physical alarm if it overheats. &lt;br /&gt;
&lt;br /&gt;
Create a new workspace (&amp;lt;code&amp;gt;sdpt-lab4&amp;lt;/code&amp;gt;). Create &amp;lt;code&amp;gt;include/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;src/&amp;lt;/code&amp;gt; directories. Populate them with these three files:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;include/ISensor.h&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (The Hardware Interface)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
// Pure virtual interface. We DO NOT implement hardware logic here.&lt;br /&gt;
class ISensor {&lt;br /&gt;
public:&lt;br /&gt;
    virtual float read_temperature() = 0;&lt;br /&gt;
    virtual ~ISensor() = default;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;include/OvenController.h&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (The Logic Module)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;quot;ISensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
class OvenController {&lt;br /&gt;
private:&lt;br /&gt;
    ISensor* temp_sensor;&lt;br /&gt;
    bool alarm_active;&lt;br /&gt;
    float max_safe_temp;&lt;br /&gt;
&lt;br /&gt;
public:&lt;br /&gt;
    // Constructor uses Dependency Injection!&lt;br /&gt;
    OvenController(ISensor* sensor, float safe_limit = 250.0f);&lt;br /&gt;
    &lt;br /&gt;
    void check_safety();&lt;br /&gt;
    bool is_alarm_active() const;&lt;br /&gt;
    &lt;br /&gt;
    // Pure math function&lt;br /&gt;
    static float raw_adc_to_celsius(int adc_value);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;src/OvenController.cpp&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (The Buggy Implementation)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/OvenController.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
OvenController::OvenController(ISensor* sensor, float safe_limit) &lt;br /&gt;
    : temp_sensor(sensor), alarm_active(false), max_safe_temp(safe_limit) {}&lt;br /&gt;
&lt;br /&gt;
void OvenController::check_safety() {&lt;br /&gt;
    float current_temp = temp_sensor-&amp;gt;read_temperature();&lt;br /&gt;
    &lt;br /&gt;
    // BUG 1: It only triggers if STRICTLY greater. What if it equals the limit?&lt;br /&gt;
    if (current_temp &amp;gt; max_safe_temp) {&lt;br /&gt;
        alarm_active = true;&lt;br /&gt;
    } else {&lt;br /&gt;
        alarm_active = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bool OvenController::is_alarm_active() const {&lt;br /&gt;
    return alarm_active;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
float OvenController::raw_adc_to_celsius(int adc_value) {&lt;br /&gt;
    // BUG 2: Integer division truncates the decimal! (e.g., 5/2 = 2, not 2.5)&lt;br /&gt;
    return (adc_value / 4095) * 330.0f; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Challenge 1: The Verification Build System (Estimated: 20 mins) ===&lt;br /&gt;
We need a build system that fetches Google Test and compiles our code with coverage instrumentation.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Create a &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; in the root directory.&lt;br /&gt;
# Build a static library named &amp;lt;code&amp;gt;oven_lib&amp;lt;/code&amp;gt; containing &amp;lt;code&amp;gt;src/OvenController.cpp&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Use &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt; to pull Google Test (&amp;lt;code&amp;gt;https://github.com/google/googletest.git&amp;lt;/code&amp;gt;, tag &amp;lt;code&amp;gt;v1.13.0&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Create an executable named &amp;lt;code&amp;gt;unit_tests&amp;lt;/code&amp;gt;. (You will create &amp;lt;code&amp;gt;tests/test_oven.cpp&amp;lt;/code&amp;gt; in the next step).&lt;br /&gt;
# Link &amp;lt;code&amp;gt;oven_lib&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;gtest_main&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;gmock&amp;lt;/code&amp;gt; to your test executable.&lt;br /&gt;
# Add the CMake logic to inject &amp;lt;code&amp;gt;-O0 -g --coverage&amp;lt;/code&amp;gt; ONLY if the build type is &amp;quot;Debug&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;cmake -DCMAKE_BUILD_TYPE=Debug ..&amp;lt;/code&amp;gt; inside your build folder. It must configure without errors and download GTest.&lt;br /&gt;
&lt;br /&gt;
=== Challenge 2: Pure Math TDD (Estimated: 25 mins) ===&lt;br /&gt;
Let&amp;#039;s catch the integer division bug using the Red-Green-Refactor cycle.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Create a &amp;lt;code&amp;gt;tests/&amp;lt;/code&amp;gt; directory and a &amp;lt;code&amp;gt;tests/test_oven.cpp&amp;lt;/code&amp;gt; file.&lt;br /&gt;
# Include &amp;lt;code&amp;gt;&amp;lt;gtest/gtest.h&amp;gt;&amp;lt;/code&amp;gt; and your &amp;lt;code&amp;gt;OvenController.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Write a &amp;lt;code&amp;gt;TEST(MathTest, ConvertsADCToCelsius)&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Use &amp;lt;code&amp;gt;EXPECT_FLOAT_EQ&amp;lt;/code&amp;gt; to assert that an ADC value of &amp;lt;code&amp;gt;2047&amp;lt;/code&amp;gt; (roughly half of 4095) returns approximately &amp;lt;code&amp;gt;164.957f&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compile and run &amp;lt;code&amp;gt;./unit_tests&amp;lt;/code&amp;gt;. (Watch it fail! This is the RED phase).&lt;br /&gt;
# Refactor &amp;lt;code&amp;gt;OvenController.cpp&amp;lt;/code&amp;gt; to fix the integer division bug. Recompile. (Watch it pass! This is the GREEN phase).&lt;br /&gt;
&lt;br /&gt;
=== Challenge 3: Hardware Mocking (Estimated: 40 mins) ===&lt;br /&gt;
We need to test &amp;lt;code&amp;gt;check_safety()&amp;lt;/code&amp;gt;, but we are on a PC. We have no I2C hardware. We must mock the &amp;lt;code&amp;gt;ISensor&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In your test file, include &amp;lt;code&amp;gt;&amp;lt;gmock/gmock.h&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Create a &amp;lt;code&amp;gt;MockSensor&amp;lt;/code&amp;gt; class that inherits from &amp;lt;code&amp;gt;ISensor&amp;lt;/code&amp;gt;. Use &amp;lt;code&amp;gt;MOCK_METHOD&amp;lt;/code&amp;gt; to mock &amp;lt;code&amp;gt;read_temperature&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Write a &amp;lt;code&amp;gt;TEST(SafetyTest, TriggersAlarmOnOverheat)&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Arrange:&amp;#039;&amp;#039;&amp;#039; Instantiate the MockSensor. Instantiate the OvenController, injecting the mock sensor into it with a safe limit of 250.0f.&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Expectation:&amp;#039;&amp;#039;&amp;#039; Program the mock to return &amp;lt;code&amp;gt;260.0f&amp;lt;/code&amp;gt; when called.&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Act:&amp;#039;&amp;#039;&amp;#039; Call &amp;lt;code&amp;gt;check_safety()&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Assert:&amp;#039;&amp;#039;&amp;#039; Expect that &amp;lt;code&amp;gt;is_alarm_active()&amp;lt;/code&amp;gt; is true.&lt;br /&gt;
# Write a second test: &amp;lt;code&amp;gt;TEST(SafetyTest, TriggersAlarmExactlyAtLimit)&amp;lt;/code&amp;gt;. &lt;br /&gt;
#* Program the mock to return exactly &amp;lt;code&amp;gt;250.0f&amp;lt;/code&amp;gt;. &lt;br /&gt;
#* Run the test. It will FAIL due to Bug 1. Fix the production code so it triggers on `&amp;gt;=`.&lt;br /&gt;
&lt;br /&gt;
=== Challenge 4: The Coverage Report (Estimated: 15 mins) ===&lt;br /&gt;
Did we test every branch of our code? Let&amp;#039;s prove it mathematically.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Ensure you have run &amp;lt;code&amp;gt;./unit_tests&amp;lt;/code&amp;gt; at least once so the &amp;lt;code&amp;gt;.gcda&amp;lt;/code&amp;gt; files are generated.&lt;br /&gt;
# Run the &amp;lt;code&amp;gt;gcovr&amp;lt;/code&amp;gt; command provided in the Theoretical Reference section.&lt;br /&gt;
# Open the resulting &amp;lt;code&amp;gt;coverage.html&amp;lt;/code&amp;gt; file in your web browser. Check that you have achieved 100% branch coverage.&lt;br /&gt;
&lt;br /&gt;
== Submission and Evaluation (Moodle VPL) ==&lt;br /&gt;
For this lab, your work will be automatically graded by the Moodle Virtual Programming Lab (VPL) engine. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;How to submit:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Ensure your code compiles locally and all tests pass (Green).&lt;br /&gt;
# Do &amp;#039;&amp;#039;&amp;#039;NOT&amp;#039;&amp;#039;&amp;#039; upload your &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory or any generated HTML files.&lt;br /&gt;
# Select the following files from your workspace:&lt;br /&gt;
#* &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;include/ISensor.h&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;include/OvenController.h&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;src/OvenController.cpp&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;tests/test_oven.cpp&amp;lt;/code&amp;gt;&lt;br /&gt;
# Package these files into a single &amp;lt;code&amp;gt;.zip&amp;lt;/code&amp;gt; archive (maintaining the folder structure).&lt;br /&gt;
# Go to the Lab 4 assignment on Moodle and upload your &amp;lt;code&amp;gt;.zip&amp;lt;/code&amp;gt; file into the VPL submission portal.&lt;br /&gt;
# Click the &amp;#039;&amp;#039;&amp;#039;Evaluate&amp;#039;&amp;#039;&amp;#039; button.&lt;br /&gt;
&lt;br /&gt;
The VPL server will automatically compile your CMake project, execute your Google Tests, and run &amp;lt;code&amp;gt;gcovr&amp;lt;/code&amp;gt;. Your grade will be calculated based on the number of passing tests and the percentage of branch coverage achieved.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_4&amp;diff=8298</id>
		<title>SDPT Lab 4</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_4&amp;diff=8298"/>
		<updated>2026-03-23T13:27:18Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: = Lab 4: Software Verification - TDD, Mocking, and Code Coverage =  == Introduction == In traditional embedded systems, testing involves compiling code, flashing it to a board, and...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 4: Software Verification - TDD, Mocking, and Code Coverage =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
In traditional embedded systems, testing involves compiling code, flashing it to a board, and physically observing the hardware. This is slow, expensive, and scales poorly. Today, we implement &amp;quot;Shift-Left Testing.&amp;quot; We will verify our C++ logic on our Host PC using automated frameworks before it ever touches a microcontroller.&lt;br /&gt;
&lt;br /&gt;
=== Goals ===&lt;br /&gt;
* Integrate Google Test and Google Mock via CMake.&lt;br /&gt;
* Write Unit Tests using the AAA (Arrange, Act, Assert) pattern.&lt;br /&gt;
* Use Dependency Injection to decouple business logic from hardware registers.&lt;br /&gt;
* Simulate hardware interactions using Google Mock (GMock).&lt;br /&gt;
* Generate interactive HTML Code Coverage reports using &amp;lt;code&amp;gt;gcovr&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Part 1: Theoretical Reference ==&lt;br /&gt;
&amp;#039;&amp;#039;Use this section as a reference manual to complete the challenges in Part 2.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Google Test &amp;amp; Mock Cheat Sheet ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Basic Assertions:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;lt;code&amp;gt;EXPECT_EQ(actual, expected);&amp;lt;/code&amp;gt; (Non-fatal equality check)&lt;br /&gt;
* &amp;lt;code&amp;gt;EXPECT_FLOAT_EQ(actual, expected);&amp;lt;/code&amp;gt; (Safe float comparison)&lt;br /&gt;
* &amp;lt;code&amp;gt;EXPECT_TRUE(condition);&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Mocking an Interface (GMock):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class MockSensor : public ISensor {&lt;br /&gt;
public:&lt;br /&gt;
    // MOCK_METHOD(ReturnType, MethodName, (Arguments), (override));&lt;br /&gt;
    MOCK_METHOD(float, read_temperature, (), (override));&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Setting Mock Expectations:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MockSensor fake_sensor;&lt;br /&gt;
// Program the mock to return 45.0 exactly twice.&lt;br /&gt;
EXPECT_CALL(fake_sensor, read_temperature())&lt;br /&gt;
    .Times(2)&lt;br /&gt;
    .WillRepeatedly(testing::Return(45.0f));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 CMake Debug &amp;amp; Coverage Setup ===&lt;br /&gt;
Coverage mathematically requires a completely unoptimized binary mapping exactly to your source code lines.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(CMAKE_BUILD_TYPE STREQUAL &amp;quot;Debug&amp;quot;)&lt;br /&gt;
    target_compile_options(my_target PRIVATE -O0 -g --coverage)&lt;br /&gt;
    target_link_options(my_target PRIVATE --coverage)&lt;br /&gt;
endif()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Running gcovr ===&lt;br /&gt;
Execute this from inside your &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory after running the tests:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
gcovr -r ../ . --html --html-details -o coverage.html -e &amp;quot;.*_deps.*&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Part 2: The Challenges ==&lt;br /&gt;
&lt;br /&gt;
=== Setup: The Raw Materials ===&lt;br /&gt;
You are building the safety controller for an industrial oven. It must read temperatures from an I2C sensor and trigger a physical alarm if it overheats. &lt;br /&gt;
&lt;br /&gt;
Create a new workspace (&amp;lt;code&amp;gt;sdpt-lab4&amp;lt;/code&amp;gt;). Create &amp;lt;code&amp;gt;include/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;src/&amp;lt;/code&amp;gt; directories. Populate them with these three files:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;include/ISensor.h&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (The Hardware Interface)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
// Pure virtual interface. We DO NOT implement hardware logic here.&lt;br /&gt;
class ISensor {&lt;br /&gt;
public:&lt;br /&gt;
    virtual float read_temperature() = 0;&lt;br /&gt;
    virtual ~ISensor() = default;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;include/OvenController.h&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (The Logic Module)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;quot;ISensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
class OvenController {&lt;br /&gt;
private:&lt;br /&gt;
    ISensor* temp_sensor;&lt;br /&gt;
    bool alarm_active;&lt;br /&gt;
    float max_safe_temp;&lt;br /&gt;
&lt;br /&gt;
public:&lt;br /&gt;
    // Constructor uses Dependency Injection!&lt;br /&gt;
    OvenController(ISensor* sensor, float safe_limit = 250.0f);&lt;br /&gt;
    &lt;br /&gt;
    void check_safety();&lt;br /&gt;
    bool is_alarm_active() const;&lt;br /&gt;
    &lt;br /&gt;
    // Pure math function&lt;br /&gt;
    static float raw_adc_to_celsius(int adc_value);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;src/OvenController.cpp&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (The Buggy Implementation)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/OvenController.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
OvenController::OvenController(ISensor* sensor, float safe_limit) &lt;br /&gt;
    : temp_sensor(sensor), alarm_active(false), max_safe_temp(safe_limit) {}&lt;br /&gt;
&lt;br /&gt;
void OvenController::check_safety() {&lt;br /&gt;
    float current_temp = temp_sensor-&amp;gt;read_temperature();&lt;br /&gt;
    &lt;br /&gt;
    // BUG 1: It only triggers if STRICTLY greater. What if it equals the limit?&lt;br /&gt;
    if (current_temp &amp;gt; max_safe_temp) {&lt;br /&gt;
        alarm_active = true;&lt;br /&gt;
    } else {&lt;br /&gt;
        alarm_active = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bool OvenController::is_alarm_active() const {&lt;br /&gt;
    return alarm_active;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
float OvenController::raw_adc_to_celsius(int adc_value) {&lt;br /&gt;
    // BUG 2: Integer division truncates the decimal! (e.g., 5/2 = 2, not 2.5)&lt;br /&gt;
    return (adc_value / 4095) * 330.0f; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Challenge 1: The Verification Build System (Estimated: 20 mins) ===&lt;br /&gt;
We need a build system that fetches Google Test and compiles our code with coverage instrumentation.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Create a &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; in the root directory.&lt;br /&gt;
# Build a static library named &amp;lt;code&amp;gt;oven_lib&amp;lt;/code&amp;gt; containing &amp;lt;code&amp;gt;src/OvenController.cpp&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Use &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt; to pull Google Test (&amp;lt;code&amp;gt;https://github.com/google/googletest.git&amp;lt;/code&amp;gt;, tag &amp;lt;code&amp;gt;v1.13.0&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Create an executable named &amp;lt;code&amp;gt;unit_tests&amp;lt;/code&amp;gt;. (You will create &amp;lt;code&amp;gt;tests/test_oven.cpp&amp;lt;/code&amp;gt; in the next step).&lt;br /&gt;
# Link &amp;lt;code&amp;gt;oven_lib&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;gtest_main&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;gmock&amp;lt;/code&amp;gt; to your test executable.&lt;br /&gt;
# Add the CMake logic to inject &amp;lt;code&amp;gt;-O0 -g --coverage&amp;lt;/code&amp;gt; ONLY if the build type is &amp;quot;Debug&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; Run &amp;lt;code&amp;gt;cmake -DCMAKE_BUILD_TYPE=Debug ..&amp;lt;/code&amp;gt; inside your build folder. It must configure without errors and download GTest.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Challenge 2: Pure Math TDD (Estimated: 25 mins) ===&lt;br /&gt;
Let&amp;#039;s catch the integer division bug using the Red-Green-Refactor cycle.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Create a &amp;lt;code&amp;gt;tests/&amp;lt;/code&amp;gt; directory and a &amp;lt;code&amp;gt;tests/test_oven.cpp&amp;lt;/code&amp;gt; file.&lt;br /&gt;
# Include &amp;lt;code&amp;gt;&amp;lt;gtest/gtest.h&amp;gt;&amp;lt;/code&amp;gt; and your &amp;lt;code&amp;gt;OvenController.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Write a &amp;lt;code&amp;gt;TEST(MathTest, ConvertsADCToCelsius)&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Use &amp;lt;code&amp;gt;EXPECT_FLOAT_EQ&amp;lt;/code&amp;gt; to assert that an ADC value of &amp;lt;code&amp;gt;2047&amp;lt;/code&amp;gt; (roughly half of 4095) returns approximately &amp;lt;code&amp;gt;164.957f&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compile and run &amp;lt;code&amp;gt;./unit_tests&amp;lt;/code&amp;gt;. (Watch it fail! This is the RED phase).&lt;br /&gt;
# Refactor &amp;lt;code&amp;gt;OvenController.cpp&amp;lt;/code&amp;gt; to fix the integer division bug. Recompile. (Watch it pass! This is the GREEN phase).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Challenge 3: Hardware Mocking (Estimated: 40 mins) ===&lt;br /&gt;
We need to test &amp;lt;code&amp;gt;check_safety()&amp;lt;/code&amp;gt;, but we are on a PC. We have no I2C hardware. We must mock the &amp;lt;code&amp;gt;ISensor&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In your test file, include &amp;lt;code&amp;gt;&amp;lt;gmock/gmock.h&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Create a &amp;lt;code&amp;gt;MockSensor&amp;lt;/code&amp;gt; class that inherits from &amp;lt;code&amp;gt;ISensor&amp;lt;/code&amp;gt;. Use &amp;lt;code&amp;gt;MOCK_METHOD&amp;lt;/code&amp;gt; to mock &amp;lt;code&amp;gt;read_temperature&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Write a &amp;lt;code&amp;gt;TEST(SafetyTest, TriggersAlarmOnOverheat)&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Arrange:&amp;#039;&amp;#039;&amp;#039; Instantiate the MockSensor. Instantiate the OvenController, injecting the mock sensor into it with a safe limit of 250.0f.&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Expectation:&amp;#039;&amp;#039;&amp;#039; Program the mock to return &amp;lt;code&amp;gt;260.0f&amp;lt;/code&amp;gt; when called.&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Act:&amp;#039;&amp;#039;&amp;#039; Call &amp;lt;code&amp;gt;check_safety()&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Assert:&amp;#039;&amp;#039;&amp;#039; Expect that &amp;lt;code&amp;gt;is_alarm_active()&amp;lt;/code&amp;gt; is true.&lt;br /&gt;
# Write a second test: &amp;lt;code&amp;gt;TEST(SafetyTest, TriggersAlarmExactlyAtLimit)&amp;lt;/code&amp;gt;. &lt;br /&gt;
#* Program the mock to return exactly &amp;lt;code&amp;gt;250.0f&amp;lt;/code&amp;gt;. &lt;br /&gt;
#* Run the test. It will FAIL due to Bug 1. Fix the production code so it triggers on `&amp;gt;=`.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Challenge 4: The Coverage Report (Estimated: 15 mins) ===&lt;br /&gt;
Did we test every branch of our code? Let&amp;#039;s prove it mathematically.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# Ensure you have run &amp;lt;code&amp;gt;./unit_tests&amp;lt;/code&amp;gt; at least once so the &amp;lt;code&amp;gt;.gcda&amp;lt;/code&amp;gt; files are generated.&lt;br /&gt;
# Run the &amp;lt;code&amp;gt;gcovr&amp;lt;/code&amp;gt; command provided in the Theoretical Reference section.&lt;br /&gt;
# Open the resulting &amp;lt;code&amp;gt;coverage.html&amp;lt;/code&amp;gt; file in your web browser.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; Click on the &amp;lt;code&amp;gt;OvenController.cpp&amp;lt;/code&amp;gt; file in the HTML report. You should see 100% line coverage and 100% branch coverage (green lines). If you have red lines, you are missing a test case!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Lab Evaluation ==&lt;br /&gt;
To receive full credit, call the professor/TA to your workstation and demonstrate:&lt;br /&gt;
# Run &amp;lt;code&amp;gt;./unit_tests&amp;lt;/code&amp;gt;. All tests must pass (Green).&lt;br /&gt;
# Show your test code, explaining how Dependency Injection allowed you to pass the &amp;lt;code&amp;gt;MockSensor&amp;lt;/code&amp;gt; into the controller.&lt;br /&gt;
# Open your &amp;lt;code&amp;gt;coverage.html&amp;lt;/code&amp;gt; report in the browser, demonstrating 100% branch coverage for the &amp;lt;code&amp;gt;OvenController.cpp&amp;lt;/code&amp;gt; file.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8297</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8297"/>
		<updated>2026-03-23T13:26:31Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;br /&gt;
* [[SDPT Lab 2]]&lt;br /&gt;
* [[SDPT Lab 3]]&lt;br /&gt;
* [[SDPT Lab 4]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_3&amp;diff=8292</id>
		<title>SDPT Lab 3</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_3&amp;diff=8292"/>
		<updated>2026-03-16T17:07:57Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 3: Build Automation - Makefiles and Modern CMake =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
In professional embedded development, clicking a &amp;quot;Build&amp;quot; button in an IDE is a luxury you rarely have. When working with Embedded Linux, RTOS environments, or CI/CD pipelines, you must define exactly how your source code is translated into machine code. &lt;br /&gt;
&lt;br /&gt;
This lab transitions you from manual terminal commands to scalable build automation. &lt;br /&gt;
&lt;br /&gt;
=== Goals ===&lt;br /&gt;
* Understand the C++ compilation pipeline (Preprocessing $\rightarrow$ Compilation $\rightarrow$ Linking).&lt;br /&gt;
* Master GNU Make: pattern rules, automatic variables, and header dependency generation.&lt;br /&gt;
* Master Modern CMake: out-of-source builds, targets, and static libraries.&lt;br /&gt;
* Integrate remote third-party libraries using CMake &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Part 1: Theoretical Reference ==&lt;br /&gt;
&amp;#039;&amp;#039;Use this section as a reference manual to complete the tasks in Part 2.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 1.1 GNU Make Fundamentals ===&lt;br /&gt;
Make tracks file modification timestamps to avoid recompiling code that hasn&amp;#039;t changed. A &amp;lt;code&amp;gt;Makefile&amp;lt;/code&amp;gt; consists of rules:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;make&amp;quot;&amp;gt;&lt;br /&gt;
target: dependencies&lt;br /&gt;
&amp;lt;TAB&amp;gt; command&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;(Note: Makefiles strictly require a real TAB character for indentation, not spaces!)&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Automatic Variables:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Make provides shortcuts to avoid typing duplicate filenames:&lt;br /&gt;
* &amp;lt;code&amp;gt;$@&amp;lt;/code&amp;gt; : The target filename.&lt;br /&gt;
* &amp;lt;code&amp;gt;$&amp;lt;&amp;lt;/code&amp;gt; : The first dependency.&lt;br /&gt;
* &amp;lt;code&amp;gt;$^&amp;lt;/code&amp;gt; : All dependencies (space-separated).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Pattern Rules:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Instead of writing a rule for every file, use a pattern template:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;make&amp;quot;&amp;gt;&lt;br /&gt;
%.o: %.cpp&lt;br /&gt;
	$(CXX) $(CXXFLAGS) -c $&amp;lt; -o $@&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;GCC Auto-Dependencies (The Header Problem):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
If you change a &amp;lt;code&amp;gt;.h&amp;lt;/code&amp;gt; file, Make won&amp;#039;t normally detect it because object files depend on &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; files. We ask GCC to generate dependency (&amp;lt;code&amp;gt;.d&amp;lt;/code&amp;gt;) files for us:&lt;br /&gt;
* Add &amp;lt;code&amp;gt;-MMD -MP&amp;lt;/code&amp;gt; to your &amp;lt;code&amp;gt;CXXFLAGS&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Include the generated files at the bottom of your Makefile using: &amp;lt;code&amp;gt;-include $(DEPS)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Modern CMake Fundamentals ===&lt;br /&gt;
CMake is a meta-build system. It generates Makefiles (or Ninja files, or Visual Studio solutions) based on a high-level &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; script. Modern CMake is &amp;quot;Target-Based&amp;quot;—you define targets (executables/libraries) and attach properties to them.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Core Commands:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cmake&amp;quot;&amp;gt;&lt;br /&gt;
cmake_minimum_required(VERSION 3.10)&lt;br /&gt;
project(MyProject CXX)&lt;br /&gt;
&lt;br /&gt;
# Build an executable from source&lt;br /&gt;
add_executable(my_app main.cpp)&lt;br /&gt;
&lt;br /&gt;
# Build a static library (.a archive)&lt;br /&gt;
add_library(my_driver STATIC driver.cpp)&lt;br /&gt;
&lt;br /&gt;
# Define where a target should look for header files&lt;br /&gt;
target_include_directories(my_driver PUBLIC include/)&lt;br /&gt;
&lt;br /&gt;
# Link a library to an executable&lt;br /&gt;
target_link_libraries(my_app PRIVATE my_driver)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Out-of-Source Builds:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Never pollute your source directory with binaries. Always build in a separate folder:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake ..&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Fetching External Libraries:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
CMake can download libraries directly from Git during the configuration phase:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cmake&amp;quot;&amp;gt;&lt;br /&gt;
include(FetchContent)&lt;br /&gt;
FetchContent_Declare(&lt;br /&gt;
  json_lib&lt;br /&gt;
  GIT_REPOSITORY https://github.com/nlohmann/json.git&lt;br /&gt;
  GIT_TAG        v3.11.2&lt;br /&gt;
)&lt;br /&gt;
FetchContent_MakeAvailable(json_lib)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Useful Resources ===&lt;br /&gt;
* [https://www.gnu.org/software/make/manual/make.html GNU Make Manual]&lt;br /&gt;
* [https://cmake.org/cmake/help/latest/ CMake Official Documentation]&lt;br /&gt;
&lt;br /&gt;
== Part 2: The Challenges ==&lt;br /&gt;
&lt;br /&gt;
=== Setup: The Raw Materials ===&lt;br /&gt;
Create a new directory for this lab (&amp;lt;code&amp;gt;sdpt-lab3&amp;lt;/code&amp;gt;). Inside, create an &amp;lt;code&amp;gt;include/&amp;lt;/code&amp;gt; directory and a &amp;lt;code&amp;gt;src/&amp;lt;/code&amp;gt; directory. Populate them with the following three files to simulate an IoT sensor node.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;include/sensor.h&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
struct SensorData {&lt;br /&gt;
    int temperature;&lt;br /&gt;
    int humidity;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_sensor();&lt;br /&gt;
SensorData read_sensor();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/sensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void init_sensor() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;[Hardware] I2C Sensor Initialized.&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
SensorData read_sensor() {&lt;br /&gt;
    return {24, 60};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;src/main.cpp&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/sensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Starting IoT Node...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    init_sensor();&lt;br /&gt;
    &lt;br /&gt;
    SensorData data = read_sensor();&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Temp: &amp;quot; &amp;lt;&amp;lt; data.temperature &amp;lt;&amp;lt; &amp;quot;C, Hum: &amp;quot; &amp;lt;&amp;lt; data.humidity &amp;lt;&amp;lt; &amp;quot;%&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Challenge 1: The Scalable Makefile (Estimated time: 25 mins) ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; Write a &amp;lt;code&amp;gt;Makefile&amp;lt;/code&amp;gt; in the root directory that compiles these files into an executable named &amp;lt;code&amp;gt;iot_node.bin&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Do &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; hardcode the &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; file names. Use the &amp;lt;code&amp;gt;wildcard&amp;lt;/code&amp;gt; function to find them dynamically.&lt;br /&gt;
* Use variables for the compiler (&amp;lt;code&amp;gt;CXX&amp;lt;/code&amp;gt;) and flags (&amp;lt;code&amp;gt;CXXFLAGS&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Use Pattern Rules and Automatic Variables to compile &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Implement GCC header dependency tracking (&amp;lt;code&amp;gt;-MMD -MP&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
# Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt;. It should compile successfully. &lt;br /&gt;
# Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; again immediately. It should say &amp;quot;Nothing to be done&amp;quot;.&lt;br /&gt;
# Open &amp;lt;code&amp;gt;include/sensor.h&amp;lt;/code&amp;gt; and add a dummy integer to the &amp;lt;code&amp;gt;SensorData&amp;lt;/code&amp;gt; struct. Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; again. It MUST recompile both &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; files automatically. If it doesn&amp;#039;t, your dependency tracking is broken.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Challenge 2: Migrating to CMake (Estimated time: 20 mins) ===&lt;br /&gt;
Makefiles are not cross-platform. We are moving to CMake.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
# Run &amp;lt;code&amp;gt;make clean&amp;lt;/code&amp;gt; (or manually delete all generated &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.d&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;.bin&amp;lt;/code&amp;gt; files).&lt;br /&gt;
# Create a &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; file to build the exact same executable.&lt;br /&gt;
# Set the C++ standard to C++14.&lt;br /&gt;
# Perform an &amp;#039;&amp;#039;&amp;#039;Out-of-Source build&amp;#039;&amp;#039;&amp;#039; using a &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Your root directory should contain only your source files and the &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;. Inside the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory, running &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; should yield the executable.&lt;br /&gt;
&lt;br /&gt;
=== Challenge 3: Modular Architecture (Estimated time: 25 mins) ===&lt;br /&gt;
Dumping all source files into a single executable is bad practice. Hardware drivers should be isolated into static libraries.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; Modify your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Remove &amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt; from your executable target.&lt;br /&gt;
# Create a new STATIC library target named &amp;lt;code&amp;gt;sensor_driver&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Attach the &amp;lt;code&amp;gt;include/&amp;lt;/code&amp;gt; directory to this library target using &amp;lt;code&amp;gt;target_include_directories&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Link the &amp;lt;code&amp;gt;sensor_driver&amp;lt;/code&amp;gt; library to your main executable.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; inside the build folder. You must see it compile &amp;lt;code&amp;gt;libsensor_driver.a&amp;lt;/code&amp;gt; first, and then link it to the main executable.&lt;br /&gt;
&lt;br /&gt;
=== Challenge 4: Third-Party Git Dependencies (Estimated time: 30 mins) ===&lt;br /&gt;
Our IoT node needs to transmit its data as a JSON payload, but writing a JSON parser from scratch is inefficient. &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
# Use CMake&amp;#039;s &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt; module to download the popular &amp;quot;Nlohmann JSON&amp;quot; library directly from GitHub.&lt;br /&gt;
#* Repo: &amp;lt;code&amp;gt;https://github.com/nlohmann/json.git&amp;lt;/code&amp;gt;&lt;br /&gt;
#* Tag: &amp;lt;code&amp;gt;v3.11.2&amp;lt;/code&amp;gt;&lt;br /&gt;
# Link the imported target (&amp;lt;code&amp;gt;nlohmann_json::nlohmann_json&amp;lt;/code&amp;gt;) to your main executable.&lt;br /&gt;
# Modify &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; to include &amp;lt;code&amp;gt;&amp;lt;nlohmann/json.hpp&amp;gt;&amp;lt;/code&amp;gt;. Serialize your &amp;lt;code&amp;gt;SensorData&amp;lt;/code&amp;gt; into a JSON object and print it to the console using &amp;lt;code&amp;gt;.dump(4)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Running your executable should print a perfectly formatted, multi-line JSON string representing your sensor data. Check &amp;lt;code&amp;gt;build/_deps/&amp;lt;/code&amp;gt; to see the downloaded source code.&lt;br /&gt;
&lt;br /&gt;
== Lab Evaluation ==&lt;br /&gt;
To receive full credit, submit the following elements on Moodle:&lt;br /&gt;
# Final version of the Makefile.&lt;br /&gt;
# Final version of the CMakeLists.txt.&lt;br /&gt;
# Screenshot of the console output of your executable printing the JSON payload.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_3&amp;diff=8291</id>
		<title>SDPT Lab 3</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_3&amp;diff=8291"/>
		<updated>2026-03-15T22:46:16Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 3: Build Automation - Makefiles and Modern CMake =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
In professional embedded development, clicking a &amp;quot;Build&amp;quot; button in an IDE is a luxury you rarely have. When working with Embedded Linux, RTOS environments, or CI/CD pipelines, you must define exactly how your source code is translated into machine code. &lt;br /&gt;
&lt;br /&gt;
This lab transitions you from manual terminal commands to scalable build automation. &lt;br /&gt;
&lt;br /&gt;
=== Goals ===&lt;br /&gt;
* Understand the C++ compilation pipeline (Preprocessing $\rightarrow$ Compilation $\rightarrow$ Linking).&lt;br /&gt;
* Master GNU Make: pattern rules, automatic variables, and header dependency generation.&lt;br /&gt;
* Master Modern CMake: out-of-source builds, targets, and static libraries.&lt;br /&gt;
* Integrate remote third-party libraries using CMake &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Part 1: Theoretical Reference ==&lt;br /&gt;
&amp;#039;&amp;#039;Use this section as a reference manual to complete the tasks in Part 2.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 1.1 GNU Make Fundamentals ===&lt;br /&gt;
Make tracks file modification timestamps to avoid recompiling code that hasn&amp;#039;t changed. A &amp;lt;code&amp;gt;Makefile&amp;lt;/code&amp;gt; consists of rules:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;make&amp;quot;&amp;gt;&lt;br /&gt;
target: dependencies&lt;br /&gt;
&amp;lt;TAB&amp;gt; command&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;(Note: Makefiles strictly require a real TAB character for indentation, not spaces!)&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Automatic Variables:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Make provides shortcuts to avoid typing duplicate filenames:&lt;br /&gt;
* &amp;lt;code&amp;gt;$@&amp;lt;/code&amp;gt; : The target filename.&lt;br /&gt;
* &amp;lt;code&amp;gt;$&amp;lt;&amp;lt;/code&amp;gt; : The first dependency.&lt;br /&gt;
* &amp;lt;code&amp;gt;$^&amp;lt;/code&amp;gt; : All dependencies (space-separated).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Pattern Rules:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Instead of writing a rule for every file, use a pattern template:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;make&amp;quot;&amp;gt;&lt;br /&gt;
%.o: %.cpp&lt;br /&gt;
	$(CXX) $(CXXFLAGS) -c $&amp;lt; -o $@&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;GCC Auto-Dependencies (The Header Problem):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
If you change a &amp;lt;code&amp;gt;.h&amp;lt;/code&amp;gt; file, Make won&amp;#039;t normally detect it because object files depend on &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; files. We ask GCC to generate dependency (&amp;lt;code&amp;gt;.d&amp;lt;/code&amp;gt;) files for us:&lt;br /&gt;
* Add &amp;lt;code&amp;gt;-MMD -MP&amp;lt;/code&amp;gt; to your &amp;lt;code&amp;gt;CXXFLAGS&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Include the generated files at the bottom of your Makefile using: &amp;lt;code&amp;gt;-include $(DEPS)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Modern CMake Fundamentals ===&lt;br /&gt;
CMake is a meta-build system. It generates Makefiles (or Ninja files, or Visual Studio solutions) based on a high-level &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; script. Modern CMake is &amp;quot;Target-Based&amp;quot;—you define targets (executables/libraries) and attach properties to them.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Core Commands:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cmake&amp;quot;&amp;gt;&lt;br /&gt;
cmake_minimum_required(VERSION 3.10)&lt;br /&gt;
project(MyProject CXX)&lt;br /&gt;
&lt;br /&gt;
# Build an executable from source&lt;br /&gt;
add_executable(my_app main.cpp)&lt;br /&gt;
&lt;br /&gt;
# Build a static library (.a archive)&lt;br /&gt;
add_library(my_driver STATIC driver.cpp)&lt;br /&gt;
&lt;br /&gt;
# Define where a target should look for header files&lt;br /&gt;
target_include_directories(my_driver PUBLIC include/)&lt;br /&gt;
&lt;br /&gt;
# Link a library to an executable&lt;br /&gt;
target_link_libraries(my_app PRIVATE my_driver)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Out-of-Source Builds:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Never pollute your source directory with binaries. Always build in a separate folder:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake ..&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Fetching External Libraries:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
CMake can download libraries directly from Git during the configuration phase:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cmake&amp;quot;&amp;gt;&lt;br /&gt;
include(FetchContent)&lt;br /&gt;
FetchContent_Declare(&lt;br /&gt;
  json_lib&lt;br /&gt;
  GIT_REPOSITORY https://github.com/nlohmann/json.git&lt;br /&gt;
  GIT_TAG        v3.11.2&lt;br /&gt;
)&lt;br /&gt;
FetchContent_MakeAvailable(json_lib)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Useful Resources ===&lt;br /&gt;
* [https://www.gnu.org/software/make/manual/make.html GNU Make Manual]&lt;br /&gt;
* [https://cmake.org/cmake/help/latest/ CMake Official Documentation]&lt;br /&gt;
&lt;br /&gt;
== Part 2: The Challenges ==&lt;br /&gt;
&lt;br /&gt;
=== Setup: The Raw Materials ===&lt;br /&gt;
Create a new directory for this lab (&amp;lt;code&amp;gt;sdpt-lab3&amp;lt;/code&amp;gt;). Inside, create an &amp;lt;code&amp;gt;include/&amp;lt;/code&amp;gt; directory and a &amp;lt;code&amp;gt;src/&amp;lt;/code&amp;gt; directory. Populate them with the following three files to simulate an IoT sensor node.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;include/sensor.h&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
struct SensorData {&lt;br /&gt;
    int temperature;&lt;br /&gt;
    int humidity;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_sensor();&lt;br /&gt;
SensorData read_sensor();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/sensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void init_sensor() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;[Hardware] I2C Sensor Initialized.&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
SensorData read_sensor() {&lt;br /&gt;
    return {24, 60};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;src/main.cpp&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/sensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Starting IoT Node...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    init_sensor();&lt;br /&gt;
    &lt;br /&gt;
    SensorData data = read_sensor();&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Temp: &amp;quot; &amp;lt;&amp;lt; data.temperature &amp;lt;&amp;lt; &amp;quot;C, Hum: &amp;quot; &amp;lt;&amp;lt; data.humidity &amp;lt;&amp;lt; &amp;quot;%&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Challenge 1: The Scalable Makefile (Estimated time: 25 mins) ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; Write a &amp;lt;code&amp;gt;Makefile&amp;lt;/code&amp;gt; in the root directory that compiles these files into an executable named &amp;lt;code&amp;gt;iot_node.bin&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Do &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; hardcode the &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; file names. Use the &amp;lt;code&amp;gt;wildcard&amp;lt;/code&amp;gt; function to find them dynamically.&lt;br /&gt;
* Use variables for the compiler (&amp;lt;code&amp;gt;CXX&amp;lt;/code&amp;gt;) and flags (&amp;lt;code&amp;gt;CXXFLAGS&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Use Pattern Rules and Automatic Variables to compile &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Implement GCC header dependency tracking (&amp;lt;code&amp;gt;-MMD -MP&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
# Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt;. It should compile successfully. &lt;br /&gt;
# Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; again immediately. It should say &amp;quot;Nothing to be done&amp;quot;.&lt;br /&gt;
# Open &amp;lt;code&amp;gt;include/sensor.h&amp;lt;/code&amp;gt; and add a dummy integer to the &amp;lt;code&amp;gt;SensorData&amp;lt;/code&amp;gt; struct. Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; again. It MUST recompile both &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; files automatically. If it doesn&amp;#039;t, your dependency tracking is broken.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Challenge 2: Migrating to CMake (Estimated time: 20 mins) ===&lt;br /&gt;
Makefiles are not cross-platform. We are moving to CMake.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
# Run &amp;lt;code&amp;gt;make clean&amp;lt;/code&amp;gt; (or manually delete all generated &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.d&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;.bin&amp;lt;/code&amp;gt; files).&lt;br /&gt;
# Create a &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; file to build the exact same executable.&lt;br /&gt;
# Set the C++ standard to C++14.&lt;br /&gt;
# Perform an &amp;#039;&amp;#039;&amp;#039;Out-of-Source build&amp;#039;&amp;#039;&amp;#039; using a &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Your root directory should contain only your source files and the &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;. Inside the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory, running &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; should yield the executable.&lt;br /&gt;
&lt;br /&gt;
=== Challenge 3: Modular Architecture (Estimated time: 25 mins) ===&lt;br /&gt;
Dumping all source files into a single executable is bad practice. Hardware drivers should be isolated into static libraries.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; Modify your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Remove &amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt; from your executable target.&lt;br /&gt;
# Create a new STATIC library target named &amp;lt;code&amp;gt;sensor_driver&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Attach the &amp;lt;code&amp;gt;include/&amp;lt;/code&amp;gt; directory to this library target using &amp;lt;code&amp;gt;target_include_directories&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Link the &amp;lt;code&amp;gt;sensor_driver&amp;lt;/code&amp;gt; library to your main executable.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; inside the build folder. You must see it compile &amp;lt;code&amp;gt;libsensor_driver.a&amp;lt;/code&amp;gt; first, and then link it to the main executable.&lt;br /&gt;
&lt;br /&gt;
=== Challenge 4: Third-Party Git Dependencies (Estimated time: 30 mins) ===&lt;br /&gt;
Our IoT node needs to transmit its data as a JSON payload, but writing a JSON parser from scratch is inefficient. &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
# Use CMake&amp;#039;s &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt; module to download the popular &amp;quot;Nlohmann JSON&amp;quot; library directly from GitHub.&lt;br /&gt;
#* Repo: &amp;lt;code&amp;gt;https://github.com/nlohmann/json.git&amp;lt;/code&amp;gt;&lt;br /&gt;
#* Tag: &amp;lt;code&amp;gt;v3.11.2&amp;lt;/code&amp;gt;&lt;br /&gt;
# Link the imported target (&amp;lt;code&amp;gt;nlohmann_json::nlohmann_json&amp;lt;/code&amp;gt;) to your main executable.&lt;br /&gt;
# Modify &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; to include &amp;lt;code&amp;gt;&amp;lt;nlohmann/json.hpp&amp;gt;&amp;lt;/code&amp;gt;. Serialize your &amp;lt;code&amp;gt;SensorData&amp;lt;/code&amp;gt; into a JSON object and print it to the console using &amp;lt;code&amp;gt;.dump(4)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Running your executable should print a perfectly formatted, multi-line JSON string representing your sensor data. Check &amp;lt;code&amp;gt;build/_deps/&amp;lt;/code&amp;gt; to see the downloaded source code.&lt;br /&gt;
&lt;br /&gt;
== Lab Evaluation ==&lt;br /&gt;
To receive full credit, call the professor/TA to your workstation and demonstrate:&lt;br /&gt;
# The GCC dependency tracking working in Challenge 1 (changing a header triggers a recompile).&lt;br /&gt;
# The clean root directory, proving an Out-of-Source build.&lt;br /&gt;
# The &amp;lt;code&amp;gt;libsensor_driver.a&amp;lt;/code&amp;gt; static library file inside your build directory.&lt;br /&gt;
# The console output of your executable printing the JSON payload.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_3&amp;diff=8290</id>
		<title>SDPT Lab 3</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_3&amp;diff=8290"/>
		<updated>2026-03-15T22:43:20Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 3: Build Automation - Makefiles and Modern CMake =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
In professional embedded development, clicking a &amp;quot;Build&amp;quot; button in an IDE is a luxury you rarely have. When working with Embedded Linux, RTOS environments, or CI/CD pipelines, you must define exactly how your source code is translated into machine code. &lt;br /&gt;
&lt;br /&gt;
This lab transitions you from manual terminal commands to scalable build automation. &lt;br /&gt;
&lt;br /&gt;
=== Goals ===&lt;br /&gt;
* Understand the C++ compilation pipeline (Preprocessing $\rightarrow$ Compilation $\rightarrow$ Linking).&lt;br /&gt;
* Master GNU Make: pattern rules, automatic variables, and header dependency generation.&lt;br /&gt;
* Master Modern CMake: out-of-source builds, targets, and static libraries.&lt;br /&gt;
* Integrate remote third-party libraries using CMake &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 1: Theoretical Reference ==&lt;br /&gt;
&amp;#039;&amp;#039;Use this section as a reference manual to complete the tasks in Part 2.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 1.1 GNU Make Fundamentals ===&lt;br /&gt;
Make tracks file modification timestamps to avoid recompiling code that hasn&amp;#039;t changed. A &amp;lt;code&amp;gt;Makefile&amp;lt;/code&amp;gt; consists of rules:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;make&amp;quot;&amp;gt;&lt;br /&gt;
target: dependencies&lt;br /&gt;
&amp;lt;TAB&amp;gt; command&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;(Note: Makefiles strictly require a real TAB character for indentation, not spaces!)&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Automatic Variables:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Make provides shortcuts to avoid typing duplicate filenames:&lt;br /&gt;
* &amp;lt;code&amp;gt;$@&amp;lt;/code&amp;gt; : The target filename.&lt;br /&gt;
* &amp;lt;code&amp;gt;$&amp;lt;&amp;lt;/code&amp;gt; : The first dependency.&lt;br /&gt;
* &amp;lt;code&amp;gt;$^&amp;lt;/code&amp;gt; : All dependencies (space-separated).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Pattern Rules:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Instead of writing a rule for every file, use a pattern template:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;make&amp;quot;&amp;gt;&lt;br /&gt;
%.o: %.cpp&lt;br /&gt;
	$(CXX) $(CXXFLAGS) -c $&amp;lt; -o $@&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;GCC Auto-Dependencies (The Header Problem):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
If you change a &amp;lt;code&amp;gt;.h&amp;lt;/code&amp;gt; file, Make won&amp;#039;t normally detect it because object files depend on &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; files. We ask GCC to generate dependency (&amp;lt;code&amp;gt;.d&amp;lt;/code&amp;gt;) files for us:&lt;br /&gt;
* Add &amp;lt;code&amp;gt;-MMD -MP&amp;lt;/code&amp;gt; to your &amp;lt;code&amp;gt;CXXFLAGS&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Include the generated files at the bottom of your Makefile using: &amp;lt;code&amp;gt;-include $(DEPS)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Modern CMake Fundamentals ===&lt;br /&gt;
CMake is a meta-build system. It generates Makefiles (or Ninja files, or Visual Studio solutions) based on a high-level &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; script. Modern CMake is &amp;quot;Target-Based&amp;quot;—you define targets (executables/libraries) and attach properties to them.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Core Commands:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cmake&amp;quot;&amp;gt;&lt;br /&gt;
cmake_minimum_required(VERSION 3.10)&lt;br /&gt;
project(MyProject CXX)&lt;br /&gt;
&lt;br /&gt;
# Build an executable from source&lt;br /&gt;
add_executable(my_app main.cpp)&lt;br /&gt;
&lt;br /&gt;
# Build a static library (.a archive)&lt;br /&gt;
add_library(my_driver STATIC driver.cpp)&lt;br /&gt;
&lt;br /&gt;
# Define where a target should look for header files&lt;br /&gt;
target_include_directories(my_driver PUBLIC include/)&lt;br /&gt;
&lt;br /&gt;
# Link a library to an executable&lt;br /&gt;
target_link_libraries(my_app PRIVATE my_driver)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Out-of-Source Builds:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Never pollute your source directory with binaries. Always build in a separate folder:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake ..&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Fetching External Libraries:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
CMake can download libraries directly from Git during the configuration phase:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cmake&amp;quot;&amp;gt;&lt;br /&gt;
include(FetchContent)&lt;br /&gt;
FetchContent_Declare(&lt;br /&gt;
  json_lib&lt;br /&gt;
  GIT_REPOSITORY https://github.com/nlohmann/json.git&lt;br /&gt;
  GIT_TAG        v3.11.2&lt;br /&gt;
)&lt;br /&gt;
FetchContent_MakeAvailable(json_lib)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Useful Resources ===&lt;br /&gt;
* [https://www.gnu.org/software/make/manual/make.html GNU Make Manual]&lt;br /&gt;
* [https://cmake.org/cmake/help/latest/ CMake Official Documentation]&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 2: The Challenges ==&lt;br /&gt;
&lt;br /&gt;
=== Setup: The Raw Materials ===&lt;br /&gt;
Create a new directory for this lab (&amp;lt;code&amp;gt;sdpt-lab3&amp;lt;/code&amp;gt;). Inside, create an &amp;lt;code&amp;gt;include/&amp;lt;/code&amp;gt; directory and a &amp;lt;code&amp;gt;src/&amp;lt;/code&amp;gt; directory. Populate them with the following three files to simulate an IoT sensor node.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;include/sensor.h&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
struct SensorData {&lt;br /&gt;
    int temperature;&lt;br /&gt;
    int humidity;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_sensor();&lt;br /&gt;
SensorData read_sensor();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/sensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void init_sensor() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;[Hardware] I2C Sensor Initialized.&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
SensorData read_sensor() {&lt;br /&gt;
    return {24, 60};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;src/main.cpp&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/sensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Starting IoT Node...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    init_sensor();&lt;br /&gt;
    &lt;br /&gt;
    SensorData data = read_sensor();&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Temp: &amp;quot; &amp;lt;&amp;lt; data.temperature &amp;lt;&amp;lt; &amp;quot;C, Hum: &amp;quot; &amp;lt;&amp;lt; data.humidity &amp;lt;&amp;lt; &amp;quot;%&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== Challenge 1: The Scalable Makefile (Estimated time: 25 mins) ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; Write a &amp;lt;code&amp;gt;Makefile&amp;lt;/code&amp;gt; in the root directory that compiles these files into an executable named &amp;lt;code&amp;gt;iot_node.bin&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Do &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; hardcode the &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; file names. Use the &amp;lt;code&amp;gt;wildcard&amp;lt;/code&amp;gt; function to find them dynamically.&lt;br /&gt;
* Use variables for the compiler (&amp;lt;code&amp;gt;CXX&amp;lt;/code&amp;gt;) and flags (&amp;lt;code&amp;gt;CXXFLAGS&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Use Pattern Rules and Automatic Variables to compile &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Implement GCC header dependency tracking (&amp;lt;code&amp;gt;-MMD -MP&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
# Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt;. It should compile successfully. &lt;br /&gt;
# Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; again immediately. It should say &amp;quot;Nothing to be done&amp;quot;.&lt;br /&gt;
# Open &amp;lt;code&amp;gt;include/sensor.h&amp;lt;/code&amp;gt; and add a dummy integer to the &amp;lt;code&amp;gt;SensorData&amp;lt;/code&amp;gt; struct. Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; again. It MUST recompile both &amp;lt;code&amp;gt;.cpp&amp;lt;/code&amp;gt; files automatically. If it doesn&amp;#039;t, your dependency tracking is broken.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== Challenge 2: Migrating to CMake (Estimated time: 20 mins) ===&lt;br /&gt;
Makefiles are not cross-platform. We are moving to CMake.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
# Run &amp;lt;code&amp;gt;make clean&amp;lt;/code&amp;gt; (or manually delete all generated &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.d&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;.bin&amp;lt;/code&amp;gt; files).&lt;br /&gt;
# Create a &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; file to build the exact same executable.&lt;br /&gt;
# Set the C++ standard to C++14.&lt;br /&gt;
# Perform an &amp;#039;&amp;#039;&amp;#039;Out-of-Source build&amp;#039;&amp;#039;&amp;#039; using a &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Your root directory should contain only your source files and the &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;. Inside the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory, running &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; should yield the executable.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== Challenge 3: Modular Architecture (Estimated time: 25 mins) ===&lt;br /&gt;
Dumping all source files into a single executable is bad practice. Hardware drivers should be isolated into static libraries.&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; Modify your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Remove &amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt; from your executable target.&lt;br /&gt;
# Create a new STATIC library target named &amp;lt;code&amp;gt;sensor_driver&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Attach the &amp;lt;code&amp;gt;include/&amp;lt;/code&amp;gt; directory to this library target using &amp;lt;code&amp;gt;target_include_directories&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Link the &amp;lt;code&amp;gt;sensor_driver&amp;lt;/code&amp;gt; library to your main executable.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; inside the build folder. You must see it compile &amp;lt;code&amp;gt;libsensor_driver.a&amp;lt;/code&amp;gt; first, and then link it to the main executable.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== Challenge 4: Third-Party Git Dependencies (Estimated time: 30 mins) ===&lt;br /&gt;
Our IoT node needs to transmit its data as a JSON payload, but writing a JSON parser from scratch is inefficient. &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Your Task:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
# Use CMake&amp;#039;s &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt; module to download the popular &amp;quot;Nlohmann JSON&amp;quot; library directly from GitHub.&lt;br /&gt;
#* Repo: &amp;lt;code&amp;gt;https://github.com/nlohmann/json.git&amp;lt;/code&amp;gt;&lt;br /&gt;
#* Tag: &amp;lt;code&amp;gt;v3.11.2&amp;lt;/code&amp;gt;&lt;br /&gt;
# Link the imported target (&amp;lt;code&amp;gt;nlohmann_json::nlohmann_json&amp;lt;/code&amp;gt;) to your main executable.&lt;br /&gt;
# Modify &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; to include &amp;lt;code&amp;gt;&amp;lt;nlohmann/json.hpp&amp;gt;&amp;lt;/code&amp;gt;. Serialize your &amp;lt;code&amp;gt;SensorData&amp;lt;/code&amp;gt; into a JSON object and print it to the console using &amp;lt;code&amp;gt;.dump(4)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Verification:&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Running your executable should print a perfectly formatted, multi-line JSON string representing your sensor data. Check &amp;lt;code&amp;gt;build/_deps/&amp;lt;/code&amp;gt; to see the downloaded source code.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Lab Evaluation ==&lt;br /&gt;
To receive full credit, call the professor/TA to your workstation and demonstrate:&lt;br /&gt;
# The GCC dependency tracking working in Challenge 1 (changing a header triggers a recompile).&lt;br /&gt;
# The clean root directory, proving an Out-of-Source build.&lt;br /&gt;
# The &amp;lt;code&amp;gt;libsensor_driver.a&amp;lt;/code&amp;gt; static library file inside your build directory.&lt;br /&gt;
# The console output of your executable printing the JSON payload.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_3&amp;diff=8289</id>
		<title>SDPT Lab 3</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_3&amp;diff=8289"/>
		<updated>2026-03-15T22:37:31Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: = Lab 3: Build Systems - From GNU Make to Modern CMake =  == Introduction == In Week 2, we solved the human collaboration problem using Git. Today, we solve the compilation scaling...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 3: Build Systems - From GNU Make to Modern CMake =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
In Week 2, we solved the human collaboration problem using Git. Today, we solve the compilation scaling problem. &lt;br /&gt;
&lt;br /&gt;
As embedded projects grow from a single file to hundreds of files with external dependencies (like cryptography or networking libraries), clicking a &amp;quot;Build&amp;quot; button in an IDE or typing &amp;lt;code&amp;gt;g++ main.cpp&amp;lt;/code&amp;gt; in the terminal is no longer viable. By the end of this 2-hour lab, you will have:&lt;br /&gt;
# Written a scalable GNU Makefile using pattern rules and automatic variables.&lt;br /&gt;
# Solved the &amp;quot;Header Dependency Problem&amp;quot; using GCC&amp;#039;s &amp;lt;code&amp;gt;-MMD&amp;lt;/code&amp;gt; flags.&lt;br /&gt;
# Migrated the project to Modern CMake.&lt;br /&gt;
# Enforced clean &amp;quot;Out-of-Source&amp;quot; builds.&lt;br /&gt;
# Built a static hardware driver library and linked it to an executable.&lt;br /&gt;
# Automatically downloaded and linked a 3rd-party library directly from GitHub using CMake&amp;#039;s &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Requirement:&amp;#039;&amp;#039;&amp;#039; You may work individually or with your partner from last week.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 1: Project Setup and The GNU Make Baseline (30 Minutes) ==&lt;br /&gt;
First, we need some source code to compile. We will simulate an IoT sensor node.&lt;br /&gt;
&lt;br /&gt;
=== 1. Create the Project Workspace ===&lt;br /&gt;
Open your terminal and create a new directory:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir sdpt-lab3-builds&lt;br /&gt;
cd sdpt-lab3-builds&lt;br /&gt;
mkdir src include&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Create the Source Files ===&lt;br /&gt;
Create a header file &amp;lt;code&amp;gt;include/sensor.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef SENSOR_H&lt;br /&gt;
#define SENSOR_H&lt;br /&gt;
&lt;br /&gt;
struct SensorData {&lt;br /&gt;
    int temperature;&lt;br /&gt;
    int humidity;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_sensor();&lt;br /&gt;
SensorData read_sensor();&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the implementation file &amp;lt;code&amp;gt;src/sensor.cpp&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/sensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void init_sensor() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;[Hardware] I2C Sensor Initialized.&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
SensorData read_sensor() {&lt;br /&gt;
    SensorData data;&lt;br /&gt;
    data.temperature = 24;&lt;br /&gt;
    data.humidity = 60;&lt;br /&gt;
    return data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the main application &amp;lt;code&amp;gt;src/main.cpp&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/sensor.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Starting IoT Node...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    init_sensor();&lt;br /&gt;
    &lt;br /&gt;
    SensorData current_data = read_sensor();&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Temp: &amp;quot; &amp;lt;&amp;lt; current_data.temperature &amp;lt;&amp;lt; &amp;quot;C, Hum: &amp;quot; &amp;lt;&amp;lt; current_data.humidity &amp;lt;&amp;lt; &amp;quot;%&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Write the Scalable Makefile ===&lt;br /&gt;
In the root directory (&amp;lt;code&amp;gt;sdpt-lab3-builds/&amp;lt;/code&amp;gt;), create a file named exactly &amp;lt;code&amp;gt;Makefile&amp;lt;/code&amp;gt;. &lt;br /&gt;
&amp;#039;&amp;#039;Warning: You MUST use an actual TAB character for the indented lines, not spaces!&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CXX = g++&lt;br /&gt;
CXXFLAGS = -Wall -Wextra -O2 -MMD -MP&lt;br /&gt;
TARGET = firmware.bin&lt;br /&gt;
&lt;br /&gt;
# Dynamically find all .cpp files in the src/ directory&lt;br /&gt;
SRCS = $(wildcard src/*.cpp)&lt;br /&gt;
&lt;br /&gt;
# String substitution: convert .cpp list to .o list&lt;br /&gt;
OBJS = $(SRCS:.cpp=.o)&lt;br /&gt;
&lt;br /&gt;
# Create a list of .d (dependency) files&lt;br /&gt;
DEPS = $(OBJS:.o=.d)&lt;br /&gt;
&lt;br /&gt;
# Default rule&lt;br /&gt;
all: $(TARGET)&lt;br /&gt;
&lt;br /&gt;
# Linker rule using automatic variables ($^ = all dependencies, $@ = target)&lt;br /&gt;
$(TARGET): $(OBJS)&lt;br /&gt;
	$(CXX) $^ -o $@&lt;br /&gt;
&lt;br /&gt;
# Pattern rule to compile any .cpp into a .o file ($&amp;lt; = first dependency)&lt;br /&gt;
%.o: %.cpp&lt;br /&gt;
	$(CXX) $(CXXFLAGS) -c $&amp;lt; -o $@&lt;br /&gt;
&lt;br /&gt;
# Clean rule to remove binaries&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f $(OBJS) $(DEPS) $(TARGET)&lt;br /&gt;
&lt;br /&gt;
# Include the auto-generated GCC dependencies&lt;br /&gt;
-include $(DEPS)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Test and Inspect the Build ===&lt;br /&gt;
Run the build:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
make&lt;br /&gt;
./firmware.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, look inside your &amp;lt;code&amp;gt;src/&amp;lt;/code&amp;gt; folder. Run &amp;lt;code&amp;gt;ls src/&amp;lt;/code&amp;gt;. &lt;br /&gt;
Notice the &amp;lt;code&amp;gt;.d&amp;lt;/code&amp;gt; files? Open &amp;lt;code&amp;gt;src/main.d&amp;lt;/code&amp;gt; in a text editor. You will see that GCC automatically wrote a Makefile rule proving that &amp;lt;code&amp;gt;main.o&amp;lt;/code&amp;gt; depends on &amp;lt;code&amp;gt;sensor.h&amp;lt;/code&amp;gt;. This is how Make knows to recompile &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; if you only change the header file!&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 2: Migrating to Modern CMake (30 Minutes) ==&lt;br /&gt;
Makefiles are great, but they leave &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.d&amp;lt;/code&amp;gt; files scattered all over our source code, and they are not cross-platform. Let&amp;#039;s upgrade.&lt;br /&gt;
&lt;br /&gt;
=== 1. Clean up the Make artifacts ===&lt;br /&gt;
Run the clean rule to delete all the generated binaries from Part 1.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
make clean&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Write the CMakeLists.txt ===&lt;br /&gt;
In the root directory, create a file named &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cmake_minimum_required(VERSION 3.10)&lt;br /&gt;
project(IoTNode CXX)&lt;br /&gt;
&lt;br /&gt;
set(CMAKE_CXX_STANDARD 14)&lt;br /&gt;
set(CMAKE_CXX_STANDARD_REQUIRED ON)&lt;br /&gt;
&lt;br /&gt;
# Define the executable and its source files&lt;br /&gt;
add_executable(firmware src/main.cpp src/sensor.cpp)&lt;br /&gt;
&lt;br /&gt;
# Tell CMake where to look for header files&lt;br /&gt;
target_include_directories(firmware PRIVATE include/)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. The Out-of-Source Build ===&lt;br /&gt;
We will never compile in the root directory again. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir build&lt;br /&gt;
cd build&lt;br /&gt;
&lt;br /&gt;
# Tell CMake to read the parent directory and generate the build system&lt;br /&gt;
cmake ..&lt;br /&gt;
&lt;br /&gt;
# Execute the build&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Run your program: &amp;lt;code&amp;gt;./firmware&amp;lt;/code&amp;gt;. Notice that your &amp;lt;code&amp;gt;src/&amp;lt;/code&amp;gt; directory is completely clean. All binaries are safely isolated inside the &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 3: Modular Architecture (Static Libraries) (30 Minutes) ==&lt;br /&gt;
In professional embedded development, we don&amp;#039;t dump all source files into the executable. We build independent, reusable Static Libraries (&amp;lt;code&amp;gt;.a&amp;lt;/code&amp;gt; files) for hardware drivers.&lt;br /&gt;
&lt;br /&gt;
=== 1. Refactor CMakeLists.txt ===&lt;br /&gt;
Go back to your root directory and open &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;. Rewrite it to decouple the sensor driver from the main application:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cmake_minimum_required(VERSION 3.10)&lt;br /&gt;
project(IoTNode CXX)&lt;br /&gt;
&lt;br /&gt;
set(CMAKE_CXX_STANDARD 14)&lt;br /&gt;
&lt;br /&gt;
# 1. Build the sensor driver as a STATIC library&lt;br /&gt;
add_library(sensor_lib STATIC src/sensor.cpp)&lt;br /&gt;
&lt;br /&gt;
# 2. Attach the include directory to the library (PUBLIC means anyone who links this library gets the headers too)&lt;br /&gt;
target_include_directories(sensor_lib PUBLIC include/)&lt;br /&gt;
&lt;br /&gt;
# 3. Build the main executable (Notice we removed sensor.cpp!)&lt;br /&gt;
add_executable(firmware src/main.cpp)&lt;br /&gt;
&lt;br /&gt;
# 4. Link the library to the executable&lt;br /&gt;
target_link_libraries(firmware PRIVATE sensor_lib)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Rebuild and Verify ===&lt;br /&gt;
Go into your &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory and just run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; (CMake automatically detects the changes to CMakeLists.txt and regenerates everything).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd build&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look at the terminal output. You should see it building &amp;lt;code&amp;gt;libsensor_lib.a&amp;lt;/code&amp;gt; first, and then linking it to &amp;lt;code&amp;gt;firmware&amp;lt;/code&amp;gt;. Run &amp;lt;code&amp;gt;ls -l&amp;lt;/code&amp;gt; to verify the &amp;lt;code&amp;gt;.a&amp;lt;/code&amp;gt; archive exists.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 4: Remote 3rd-Party Dependencies (30 Minutes) ==&lt;br /&gt;
Our IoT node generates data, but we need to format it as JSON to send it over the network. Writing a JSON parser in C++ from scratch is a terrible idea. We will use a popular 3rd-party library (Nlohmann JSON) and import it directly from GitHub using CMake&amp;#039;s &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== 1. Fetching the Library ===&lt;br /&gt;
Open your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; and add the FetchContent block &amp;#039;&amp;#039;before&amp;#039;&amp;#039; your executable definition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cmake_minimum_required(VERSION 3.14) # Note: Upgraded to 3.14 for FetchContent&lt;br /&gt;
project(IoTNode CXX)&lt;br /&gt;
&lt;br /&gt;
set(CMAKE_CXX_STANDARD 14)&lt;br /&gt;
&lt;br /&gt;
# --- Define local library ---&lt;br /&gt;
add_library(sensor_lib STATIC src/sensor.cpp)&lt;br /&gt;
target_include_directories(sensor_lib PUBLIC include/)&lt;br /&gt;
&lt;br /&gt;
# --- Fetch 3rd Party Library from GitHub ---&lt;br /&gt;
include(FetchContent)&lt;br /&gt;
FetchContent_Declare(&lt;br /&gt;
  json&lt;br /&gt;
  GIT_REPOSITORY https://github.com/nlohmann/json.git&lt;br /&gt;
  GIT_TAG        v3.11.2&lt;br /&gt;
)&lt;br /&gt;
FetchContent_MakeAvailable(json)&lt;br /&gt;
&lt;br /&gt;
# --- Define Executable ---&lt;br /&gt;
add_executable(firmware src/main.cpp)&lt;br /&gt;
&lt;br /&gt;
# Link BOTH our local hardware library AND the remote JSON library&lt;br /&gt;
# (The remote library exposes a target named &amp;#039;nlohmann_json::nlohmann_json&amp;#039;)&lt;br /&gt;
target_link_libraries(firmware PRIVATE sensor_lib nlohmann_json::nlohmann_json)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Use the JSON Library in Code ===&lt;br /&gt;
Open &amp;lt;code&amp;gt;src/main.cpp&amp;lt;/code&amp;gt; and update it to serialize our sensor data:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;quot;../include/sensor.h&amp;quot;&lt;br /&gt;
#include &amp;lt;nlohmann/json.hpp&amp;gt; // Included from the fetched library!&lt;br /&gt;
&lt;br /&gt;
using json = nlohmann::json;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Starting IoT Node...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    init_sensor();&lt;br /&gt;
    &lt;br /&gt;
    SensorData current_data = read_sensor();&lt;br /&gt;
    &lt;br /&gt;
    // Create a JSON object and pack our data into it&lt;br /&gt;
    json payload;&lt;br /&gt;
    payload[&amp;quot;device_id&amp;quot;] = &amp;quot;RPI_NODE_01&amp;quot;;&lt;br /&gt;
    payload[&amp;quot;status&amp;quot;] = &amp;quot;active&amp;quot;;&lt;br /&gt;
    payload[&amp;quot;data&amp;quot;][&amp;quot;temperature&amp;quot;] = current_data.temperature;&lt;br /&gt;
    payload[&amp;quot;data&amp;quot;][&amp;quot;humidity&amp;quot;] = current_data.humidity;&lt;br /&gt;
    &lt;br /&gt;
    // Serialize and print the JSON string&lt;br /&gt;
    std::string network_message = payload.dump(4); // 4 spaces of indentation&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;\n--- Transmission Payload ---\n&amp;quot; &amp;lt;&amp;lt; network_message &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. The Final Build ===&lt;br /&gt;
Go to your &amp;lt;code&amp;gt;build/&amp;lt;/code&amp;gt; directory. Run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt;. &lt;br /&gt;
&amp;#039;&amp;#039;Note: This build will take slightly longer because CMake is reaching out to GitHub, downloading the library, and configuring it on the fly.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;./firmware&amp;lt;/code&amp;gt;. You should see a perfectly formatted JSON payload printed to your terminal!&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Lab Deliverable ==&lt;br /&gt;
To receive full credit for this week&amp;#039;s lab, demonstrate the following to your professor or TA:&lt;br /&gt;
# Run &amp;lt;code&amp;gt;./firmware&amp;lt;/code&amp;gt; to show the successful JSON serialization.&lt;br /&gt;
# Show your &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt; file demonstrating the &amp;lt;code&amp;gt;FetchContent&amp;lt;/code&amp;gt; block and &amp;lt;code&amp;gt;target_link_libraries&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Navigate to &amp;lt;code&amp;gt;build/_deps/json-src&amp;lt;/code&amp;gt; in your terminal to prove that CMake successfully downloaded the external repository into the out-of-source build tree.&lt;br /&gt;
# Explain the difference between the &amp;lt;code&amp;gt;PUBLIC&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIVATE&amp;lt;/code&amp;gt; keywords in your CMake link step.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8288</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8288"/>
		<updated>2026-03-15T22:37:25Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;br /&gt;
* [[SDPT Lab 2]]&lt;br /&gt;
* [[SDPT Lab 3]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_2&amp;diff=8282</id>
		<title>SDPT Lab 2</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_2&amp;diff=8282"/>
		<updated>2026-03-02T14:11:50Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 2: Multi-Player Git, Code Reviews, and Advanced Conflict Resolution =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
In Week 1, you learned how to drive Git in &amp;quot;single-player mode.&amp;quot; Today, we switch to &amp;quot;multi-player mode.&amp;quot; Software engineering is a team sport. When multiple engineers edit the same codebase simultaneously, collisions are inevitable, and uninterrupted work is a myth. &lt;br /&gt;
&lt;br /&gt;
By the end of this 2-hour lab, you and your partner will have:&lt;br /&gt;
# Configured a shared team repository with strict Branch Protection.&lt;br /&gt;
# Used &amp;lt;code&amp;gt;git stash&amp;lt;/code&amp;gt; to handle an emergency &amp;quot;hotfix&amp;quot; interruption.&lt;br /&gt;
# Conducted an iterative Code Review (requesting and pushing fixes).&lt;br /&gt;
# Intentionally caused a Git Merge Conflict.&lt;br /&gt;
# Resolved the conflict professionally using &amp;lt;code&amp;gt;git rebase&amp;lt;/code&amp;gt; and force-pushing.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Requirement:&amp;#039;&amp;#039;&amp;#039; Find a partner. Decide who will be &amp;#039;&amp;#039;&amp;#039;Student A (The Maintainer)&amp;#039;&amp;#039;&amp;#039; and who will be &amp;#039;&amp;#039;&amp;#039;Student B (The Developer)&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 1: Team Setup and Branch Protection (20 Minutes) ==&lt;br /&gt;
We must first create a shared workspace and establish our &amp;quot;Traffic Laws.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== 1. Create the Shared Repository (Student A) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; Log into GitLab and create a new blank project named &amp;lt;code&amp;gt;sdpt-lab2-collaboration&amp;lt;/code&amp;gt;. &lt;br /&gt;
* Uncheck &amp;quot;Initialize repository with a README&amp;quot;.&lt;br /&gt;
* On the left sidebar, go to &amp;#039;&amp;#039;&amp;#039;Manage&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Members&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Invite members&amp;#039;&amp;#039;&amp;#039;. Search for &amp;#039;&amp;#039;&amp;#039;Student B&amp;#039;&amp;#039;&amp;#039; by their university email.&lt;br /&gt;
* Assign Student B the role of &amp;#039;&amp;#039;&amp;#039;Developer&amp;#039;&amp;#039;&amp;#039; and click Invite.&lt;br /&gt;
&lt;br /&gt;
=== 2. Enforce Branch Protection (Student A) ===&lt;br /&gt;
The &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch is sacred. No one should be allowed to push code directly to it.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; In the project sidebar, go to &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Repository&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Expand the &amp;#039;&amp;#039;&amp;#039;Protected branches&amp;#039;&amp;#039;&amp;#039; section.&lt;br /&gt;
* Ensure the branch is set to &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;master&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Set &amp;#039;&amp;#039;&amp;#039;Allowed to merge&amp;#039;&amp;#039;&amp;#039; to: &amp;lt;code&amp;gt;Developers + Maintainers&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Set &amp;#039;&amp;#039;&amp;#039;Allowed to push and merge&amp;#039;&amp;#039;&amp;#039; to: &amp;lt;code&amp;gt;No one&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Protect&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
=== 3. Initialize the Baseline (Student A) ===&lt;br /&gt;
Student A will push the initial skeleton code.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir sdpt-lab2-collaboration&lt;br /&gt;
cd sdpt-lab2-collaboration&lt;br /&gt;
git init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
    // TODO: Initialize communication protocol&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Sytem Booting...&amp;quot; &amp;lt;&amp;lt; std::endl; // Notice the typo!&lt;br /&gt;
    init_hardware();&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Commit and push:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Initial baseline code&amp;quot;&lt;br /&gt;
git remote add origin git@gitlab.com:&amp;lt;Student-A-Username&amp;gt;/sdpt-lab2-collaboration.git&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Clone the Repository (Student B) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student B:&amp;#039;&amp;#039;&amp;#039; Copy the SSH clone URL from GitLab.&lt;br /&gt;
* Clone the repository to your machine:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone git@gitlab.com:&amp;lt;Student-A-Username&amp;gt;/sdpt-lab2-collaboration.git&lt;br /&gt;
cd sdpt-lab2-collaboration&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 2: The Emergency Interruption &amp;amp; Stash (20 Minutes) ==&lt;br /&gt;
Student B is going to start working on a feature, but Student A (acting as the manager) will interrupt them with an urgent bug fix.&lt;br /&gt;
&lt;br /&gt;
=== 1. Start Feature Work (Student B) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student B:&amp;#039;&amp;#039;&amp;#039; Create a branch for the I2C driver.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout -b feature-i2c&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and replace the TODO comment:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing I2C Bus on Port B...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Wait! Do not commit yet!&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 2. The Emergency (Student A) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; &amp;quot;Stop what you are doing! There is a typo in the main boot message (&amp;#039;Sytem Booting&amp;#039;). We need a hotfix immediately!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== 3. The Stash (Student B) ===&lt;br /&gt;
Student B cannot switch to the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch because they have uncommitted I2C changes. They must stash them.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git stash&lt;br /&gt;
git checkout main&lt;br /&gt;
git checkout -b hotfix-typo&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Fix the Bug (Student B) ===&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and fix the typo to say &amp;lt;code&amp;gt;&amp;quot;System Booting...&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Fix typo in boot message&amp;quot;&lt;br /&gt;
git push -u origin hotfix-typo&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student B:&amp;#039;&amp;#039;&amp;#039; Go to GitLab, open a Merge Request for the hotfix, and assign Student A.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; Review the MR, Approve it, and click &amp;#039;&amp;#039;&amp;#039;Merge&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
=== 5. Resume Work (Student B) ===&lt;br /&gt;
Student B, now that the emergency is handled, return to your feature and pop your stash.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout feature-i2c&lt;br /&gt;
git stash pop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Your I2C code has returned! Commit and push it.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Add I2C hardware initialization&amp;quot;&lt;br /&gt;
git push -u origin feature-i2c&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Open a Merge Request for &amp;lt;code&amp;gt;feature-i2c&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 3: Parallel Dev &amp;amp; Iterative Code Review (25 Minutes) ==&lt;br /&gt;
While Student B was working, Student A was supposed to be writing the SPI driver.&lt;br /&gt;
&lt;br /&gt;
=== 1. Create the Collision (Student A) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; Make sure you are on &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; and pull the latest changes (the typo fix).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout main&lt;br /&gt;
git pull origin main&lt;br /&gt;
git checkout -b feature-spi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and edit the EXACT SAME LINE that Student B edited:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing SPI Bus on Port A...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Commit, push, and open an MR.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Add SPI hardware initialization&amp;quot;&lt;br /&gt;
git push -u origin feature-spi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. The Iterative Review ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; Go to Student B&amp;#039;s Merge Request (the I2C one).&lt;br /&gt;
* Do &amp;#039;&amp;#039;&amp;#039;NOT&amp;#039;&amp;#039;&amp;#039; approve it. We are going to request a change.&lt;br /&gt;
* Go to the &amp;#039;&amp;#039;&amp;#039;Changes&amp;#039;&amp;#039;&amp;#039; tab. Click the comment bubble next to the I2C line and write: &amp;#039;&amp;#039;&amp;quot;We need to specify the baud rate here. Please add &amp;#039;at 400kHz&amp;#039; to the output.&amp;quot;&amp;#039;&amp;#039; Click &amp;#039;&amp;#039;&amp;#039;Start a review&amp;#039;&amp;#039;&amp;#039; and then &amp;#039;&amp;#039;&amp;#039;Submit review&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
=== 3. Implementing the Fix (Student B) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student B:&amp;#039;&amp;#039;&amp;#039; You received a change request. Update your code locally.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing I2C Bus on Port B at 400kHz...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Update I2C init to include baud rate per code review&amp;quot;&lt;br /&gt;
git push origin feature-i2c&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Notice that your GitLab MR automatically updates! &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; Check the MR again. The requested change is there. Click &amp;#039;&amp;#039;&amp;#039;Approve&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;Merge&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 4: The Rebase Conflict (25 Minutes) ==&lt;br /&gt;
Because Student B&amp;#039;s MR was merged first, Student A&amp;#039;s MR (SPI) is now broken. &lt;br /&gt;
&lt;br /&gt;
=== 1. Discovering the Conflict (Student A) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; Check your &amp;lt;code&amp;gt;feature-spi&amp;lt;/code&amp;gt; Merge Request on GitLab. You will see a red warning: &amp;#039;&amp;#039;&amp;#039;Merge blocked: merge conflicts must be resolved.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 2. Fetch and Rebase (Student A) ===&lt;br /&gt;
We will resolve this using the professional Trunk-Based standard: Rebasing.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Download the latest state of the remote server&lt;br /&gt;
git fetch origin&lt;br /&gt;
&lt;br /&gt;
# Replay your SPI commits on top of the newly updated main branch&lt;br /&gt;
git rebase origin/main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Git will stop and output: &amp;lt;code&amp;gt;CONFLICT (content): Merge conflict in main.cpp.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Fix the Code (Student A) ===&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt;. You will see the Git markers. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing I2C Bus on Port B at 400kHz...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
=======&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing SPI Bus on Port A...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; Add SPI hardware initialization&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Delete the markers and combine the code so BOTH interfaces initialize:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing I2C Bus on Port B at 400kHz...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing SPI Bus on Port A...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Continue and Force Push (Student A) ===&lt;br /&gt;
Stage the resolved file and tell the rebase to continue.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git rebase --continue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Because rebasing rewrites history, your local branch and the remote branch have diverged. A normal &amp;lt;code&amp;gt;git push&amp;lt;/code&amp;gt; will fail. You must force it.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git push --force origin feature-spi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5. Final Approval (Student B) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student B:&amp;#039;&amp;#039;&amp;#039; Go to Student A&amp;#039;s MR. The conflict is gone! &lt;br /&gt;
* Review the code, click &amp;#039;&amp;#039;&amp;#039;Approve&amp;#039;&amp;#039;&amp;#039;, and click &amp;#039;&amp;#039;&amp;#039;Merge&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Lab Deliverable ==&lt;br /&gt;
To receive full credit for this week&amp;#039;s lab, call the professor or TA over and demonstrate:&lt;br /&gt;
# Your GitLab MR history showing &amp;#039;&amp;#039;&amp;#039;three&amp;#039;&amp;#039;&amp;#039; merged requests (Hotfix, I2C, SPI).&lt;br /&gt;
# Inside the I2C MR, show the comment thread where a change was requested and resolved.&lt;br /&gt;
# Run &amp;lt;code&amp;gt;git log --graph --oneline&amp;lt;/code&amp;gt; on your terminal to prove the final history includes all features without broken code.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_2&amp;diff=8281</id>
		<title>SDPT Lab 2</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_2&amp;diff=8281"/>
		<updated>2026-03-02T14:04:49Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: = Lab 2: Multi-Player Git, Merge Requests, and Conflict Resolution =  == Introduction == In Week 1, you learned how to drive Git in &amp;quot;single-player mode.&amp;quot; You initialized a reposito...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 2: Multi-Player Git, Merge Requests, and Conflict Resolution =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
In Week 1, you learned how to drive Git in &amp;quot;single-player mode.&amp;quot; You initialized a repository, staged files, and pushed to your own remote server. &lt;br /&gt;
&lt;br /&gt;
Today, we switch to &amp;quot;multi-player mode.&amp;quot; Software engineering is a team sport. When multiple engineers edit the same codebase simultaneously, collisions are inevitable. By the end of this 2-hour lab, you and a partner will have:&lt;br /&gt;
# Configured a shared team repository.&lt;br /&gt;
# Enforced Trunk-Based Development by locking down the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch.&lt;br /&gt;
# Worked in parallel on feature branches.&lt;br /&gt;
# Intentionally caused a Git Merge Conflict.&lt;br /&gt;
# Resolved the conflict using Git commands and GitLab Merge Requests (MRs).&lt;br /&gt;
# Conducted a formal Code Review.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Requirement:&amp;#039;&amp;#039;&amp;#039; Find a partner. Decide who will be &amp;#039;&amp;#039;&amp;#039;Student A (The Maintainer)&amp;#039;&amp;#039;&amp;#039; and who will be &amp;#039;&amp;#039;&amp;#039;Student B (The Developer)&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 1: Team Setup and Branch Protection (20 Minutes) ==&lt;br /&gt;
We must first create a shared workspace and establish our &amp;quot;Traffic Laws&amp;quot; (Branch Protection).&lt;br /&gt;
&lt;br /&gt;
=== 1. Create the Shared Repository (Student A) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; Log into GitLab and create a new blank project named &amp;lt;code&amp;gt;sdpt-lab2-collaboration&amp;lt;/code&amp;gt;. &lt;br /&gt;
* Uncheck &amp;quot;Initialize repository with a README&amp;quot;.&lt;br /&gt;
* On the left sidebar, go to &amp;#039;&amp;#039;&amp;#039;Manage&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Members&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Invite members&amp;#039;&amp;#039;&amp;#039;. Search for &amp;#039;&amp;#039;&amp;#039;Student B&amp;#039;&amp;#039;&amp;#039; by their university email or username.&lt;br /&gt;
* Assign Student B the role of &amp;#039;&amp;#039;&amp;#039;Developer&amp;#039;&amp;#039;&amp;#039; and click Invite.&lt;br /&gt;
&lt;br /&gt;
=== 2. Enforce Branch Protection (Student A) ===&lt;br /&gt;
We are using Trunk-Based Development. The &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch is sacred. No one should be allowed to push broken code directly to it.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; In the project sidebar, go to &amp;#039;&amp;#039;&amp;#039;Settings&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Repository&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Expand the &amp;#039;&amp;#039;&amp;#039;Protected branches&amp;#039;&amp;#039;&amp;#039; section.&lt;br /&gt;
* Ensure the branch is set to &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;master&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Set &amp;#039;&amp;#039;&amp;#039;Allowed to merge&amp;#039;&amp;#039;&amp;#039; to: &amp;lt;code&amp;gt;Developers + Maintainers&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Set &amp;#039;&amp;#039;&amp;#039;Allowed to push and merge&amp;#039;&amp;#039;&amp;#039; to: &amp;lt;code&amp;gt;No one&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Protect&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&amp;#039;&amp;#039;(Now, the ONLY way code gets into main is through a Merge Request!)&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 3. Initialize the Baseline (Student A) ===&lt;br /&gt;
Student A will push the initial skeleton code so you both have a starting point.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Student A&amp;#039;s Terminal:&lt;br /&gt;
mkdir sdpt-lab2-collaboration&lt;br /&gt;
cd sdpt-lab2-collaboration&lt;br /&gt;
git init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a file named &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
    // TODO: Initialize communication protocol&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;System Booting...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    init_hardware();&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Commit and push:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Initial baseline code&amp;quot;&lt;br /&gt;
git remote add origin git@gitlab.com:&amp;lt;Student-A-Username&amp;gt;/sdpt-lab2-collaboration.git&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Clone the Repository (Student B) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student B:&amp;#039;&amp;#039;&amp;#039; Go to Student A&amp;#039;s GitLab project page. Copy the SSH clone URL.&lt;br /&gt;
* Open your terminal and clone the shared repository to your machine:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone git@gitlab.com:&amp;lt;Student-A-Username&amp;gt;/sdpt-lab2-collaboration.git&lt;br /&gt;
cd sdpt-lab2-collaboration&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 2: Parallel Realities (30 Minutes) ==&lt;br /&gt;
Both students will now create isolated branches and attempt to implement the hardware initialization logic at the exact same time.&lt;br /&gt;
&lt;br /&gt;
=== 1. Branching Out (Both Students) ===&lt;br /&gt;
Both students must run the following commands on their own machines:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Student A runs:&lt;br /&gt;
git checkout -b feature-spi-init&lt;br /&gt;
&lt;br /&gt;
# Student B runs:&lt;br /&gt;
git checkout -b feature-i2c-init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Writing the Code (Both Students) ===&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; in your text editor. Find the &amp;lt;code&amp;gt;init_hardware()&amp;lt;/code&amp;gt; function.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Student A (SPI Logic):&amp;#039;&amp;#039;&amp;#039; Replace the TODO comment with this exact code:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing SPI Bus on Port A...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Student B (I2C Logic):&amp;#039;&amp;#039;&amp;#039; Replace the TODO comment with this exact code:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing I2C Bus on Port B...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Commit and Push (Both Students) ===&lt;br /&gt;
Because you are on separate branches, you can both push to the server safely.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Student A:&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Add SPI hardware initialization&amp;quot;&lt;br /&gt;
git push -u origin feature-spi-init&lt;br /&gt;
&lt;br /&gt;
# Student B:&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Add I2C hardware initialization&amp;quot;&lt;br /&gt;
git push -u origin feature-i2c-init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Open Merge Requests (Both Students) ===&lt;br /&gt;
* Both students: Go to the GitLab project page. &lt;br /&gt;
* You should see a blue banner saying &amp;quot;You pushed to feature-...&amp;quot;. Click &amp;#039;&amp;#039;&amp;#039;Create merge request&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Assign your partner as the &amp;#039;&amp;#039;&amp;#039;Reviewer&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Create merge request&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 3: The Collision &amp;amp; Code Review (30 Minutes) ==&lt;br /&gt;
Right now, both Merge Requests look green and ready to merge. Git doesn&amp;#039;t know there is a problem yet. &lt;br /&gt;
&lt;br /&gt;
=== 1. Review and Merge Student A&amp;#039;s Code ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student B:&amp;#039;&amp;#039;&amp;#039; Go to the Merge Requests tab and click on Student A&amp;#039;s MR (SPI init).&lt;br /&gt;
* Go to the &amp;#039;&amp;#039;&amp;#039;Changes&amp;#039;&amp;#039;&amp;#039; tab to review the code.&lt;br /&gt;
* Leave a comment on the line of code: &amp;quot;Looks good, SPI is the correct protocol.&amp;quot;&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Approve&amp;#039;&amp;#039;&amp;#039;, then click the green &amp;#039;&amp;#039;&amp;#039;Merge&amp;#039;&amp;#039;&amp;#039; button.&lt;br /&gt;
&lt;br /&gt;
Student A&amp;#039;s code is now officially part of the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch! &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2. The Conflict Appears ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student B:&amp;#039;&amp;#039;&amp;#039; Go back to the Merge Requests list and open your own MR (I2C init).&lt;br /&gt;
* You will see a glaring error: &amp;#039;&amp;#039;&amp;#039;Merge blocked: merge conflicts must be resolved.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;Why did this happen?&amp;#039;&amp;#039; Both of you edited the exact same line in &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt;. Git refuses to guess whether the SPI code or the I2C code should win. A human must intervene.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 4: Resolving the Conflict (30 Minutes) ==&lt;br /&gt;
Student B must pull the new changes from the server and fix the conflict locally before they can merge.&lt;br /&gt;
&lt;br /&gt;
=== 1. Update the Local Main Branch (Student B) ===&lt;br /&gt;
Student B, your local machine does not know about Student A&amp;#039;s merged code yet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Switch back to main&lt;br /&gt;
git checkout main&lt;br /&gt;
&lt;br /&gt;
# Download the latest changes from the server&lt;br /&gt;
git pull origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Rebase or Merge? (Student B) ===&lt;br /&gt;
Switch back to your feature branch. We need to integrate the new &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; into your feature branch. We will use a merge to resolve the conflict.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout feature-i2c-init&lt;br /&gt;
git merge main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Git will output: &amp;lt;code&amp;gt;CONFLICT (content): Merge conflict in main.cpp. Automatic merge failed.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Fix the Code (Student B) ===&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; in your text editor. Git has injected markers into your code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing I2C Bus on Port B...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
=======&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing SPI Bus on Port A...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; main&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Task:&amp;#039;&amp;#039;&amp;#039; Discuss with Student A. Decide that you actually need &amp;#039;&amp;#039;both&amp;#039;&amp;#039; protocols to initialize.&lt;br /&gt;
* Delete the Git markers (&amp;lt;code&amp;gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;=======&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;) and combine the logic so it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void init_hardware() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing SPI Bus on Port A...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Initializing I2C Bus on Port B...&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Finalize the Merge (Student B) ===&lt;br /&gt;
Now that the conflict is manually fixed, tell Git it is resolved:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Resolve merge conflict between SPI and I2C initialization&amp;quot;&lt;br /&gt;
git push origin feature-i2c-init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5. Final Approval (Student A) ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Student A:&amp;#039;&amp;#039;&amp;#039; Go to Student B&amp;#039;s Merge Request on GitLab. &lt;br /&gt;
* Notice the conflict warning is gone. The MR is green again!&lt;br /&gt;
* Review the Changes to ensure both SPI and I2C are initialized.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Approve&amp;#039;&amp;#039;&amp;#039;, then click &amp;#039;&amp;#039;&amp;#039;Merge&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Lab Deliverable ==&lt;br /&gt;
To receive full credit for this week&amp;#039;s lab, both partners must call the professor or teaching assistant over to your workstation and demonstrate:&lt;br /&gt;
# The shared GitLab repository showing the &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; branch with both SPI and I2C logic combined.&lt;br /&gt;
# The &amp;#039;&amp;#039;&amp;#039;Settings -&amp;gt; Repository -&amp;gt; Protected branches&amp;#039;&amp;#039;&amp;#039; screen showing that &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; cannot be pushed to directly.&lt;br /&gt;
# The &amp;#039;&amp;#039;&amp;#039;Merge Requests&amp;#039;&amp;#039;&amp;#039; tab showing two Closed/Merged MRs with review comments visible.&lt;br /&gt;
# Run &amp;lt;code&amp;gt;git log --graph --oneline&amp;lt;/code&amp;gt; on your terminal to show the visual graph of the diverging branches and the merge commit.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8280</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8280"/>
		<updated>2026-03-02T13:42:59Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;br /&gt;
* [[SDPT Lab 2]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Main_Page&amp;diff=8279</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Main_Page&amp;diff=8279"/>
		<updated>2026-03-02T13:42:39Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Laboratories List */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The purpose of this page is the index the lab tutorials and tasks, as well as the auxiliary resources for the lectures and laboratories taught within the DCAE department.&lt;br /&gt;
&lt;br /&gt;
== Course List ==&lt;br /&gt;
&lt;br /&gt;
* [[Integrated Digital Circuits (lecture)]]&lt;br /&gt;
* [[Data Structures and Algorithms]]&lt;br /&gt;
* [[Power Semiconductor Devices]]&lt;br /&gt;
&lt;br /&gt;
== Laboratories List ==&lt;br /&gt;
* [[Advanced Digital Systems]]&lt;br /&gt;
* [[Data Structures and Algorithms (lab)]]&lt;br /&gt;
* [[Digital Integrated Circuits (lab)|Digital Integrated Circuits]]&lt;br /&gt;
* [[Digital Integrated Circuits (old lab)|Digital Integrated Circuits - old]]&lt;br /&gt;
* [[Object Oriented Programming]]&lt;br /&gt;
* [[Power Semiconductor Devices (lab)]]&lt;br /&gt;
* [https://users.dcae.pub.ro/~zhascsi/courses/dsd/dsd.html Digital Systems Design Project]&lt;br /&gt;
* [[Electronic Devices(lab)]]&lt;br /&gt;
* [[Electronic Circuits(lab)]]&lt;br /&gt;
* [[Software Development Process and Testing]]&lt;br /&gt;
&lt;br /&gt;
== Seminaries List ==&lt;br /&gt;
* [[Digital Integrated Circuits (sem)|Digital Integrated Circuits]]&lt;br /&gt;
&lt;br /&gt;
== Applications List ==&lt;br /&gt;
* [[Digital Integrated Circuits (app)|Digital Integrated Circuits]]&lt;br /&gt;
&lt;br /&gt;
== Project List ==&lt;br /&gt;
* [[Project 1 - Electronic Devices and Circuits |Electronic Devices and Circuits (Project 1)]]&lt;br /&gt;
&lt;br /&gt;
* [[Project Master |Project Master]]&lt;br /&gt;
&lt;br /&gt;
== Evaluation Forms ==&lt;br /&gt;
* [[Evaluation Forms 2014-2015, Semester I]]&lt;br /&gt;
* [[Evaluation Forms 2014-2015, Semester II]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8278</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8278"/>
		<updated>2026-03-02T13:42:03Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Rhobincu a redenumit pagina Software Development Process and Resting în Software Development Process and Testing fără a lăsa o redirecționare în loc&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_1&amp;diff=8270</id>
		<title>SDPT Lab 1</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_1&amp;diff=8270"/>
		<updated>2026-02-23T00:41:41Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Part 1: Secure Authentication (SSH Keys) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 1: Foundation of Process - Git and GitLab Basics =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Welcome to the first lab of Software Development Process and Testing (SDPT). In our lecture, we discussed why treating software like a physical breadboard leads to failure in complex systems. We introduced the Software Development Life Cycle (SDLC), Issue Tracking, and the underlying graph model of Git.&lt;br /&gt;
&lt;br /&gt;
Today, we put theory into practice. By the end of this 2-hour lab, you will have:&lt;br /&gt;
# Configured secure SSH authentication with your GitLab server.&lt;br /&gt;
# Created a project repository and your first tracked Issue.&lt;br /&gt;
# Configured Git on your local machine.&lt;br /&gt;
# Moved a C++ source file through the Three States of Git.&lt;br /&gt;
# Prevented binary files from entering your repository using &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Pushed your local history to the remote GitLab server to automatically close your Issue.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Note:&amp;#039;&amp;#039;&amp;#039; Do not rush. The goal is to understand &amp;#039;&amp;#039;where&amp;#039;&amp;#039; your files are in the Git graph at any given moment. Run &amp;lt;code&amp;gt;git status&amp;lt;/code&amp;gt; frequently!&lt;br /&gt;
&lt;br /&gt;
== Part 1: Secure Authentication (SSH Keys) ==&lt;br /&gt;
Modern code repositories do not allow you to push code using your standard web password. We must set up a secure cryptographic key pair. &lt;br /&gt;
&lt;br /&gt;
=== 1. Generate an SSH Key Pair ===&lt;br /&gt;
Open your terminal (Linux/macOS) or Git Bash (Windows) and type:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;your.university.email@stud.####.upb.ro&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Press &amp;#039;&amp;#039;&amp;#039;Enter&amp;#039;&amp;#039;&amp;#039; to accept the default file location.&lt;br /&gt;
* Press &amp;#039;&amp;#039;&amp;#039;Enter&amp;#039;&amp;#039;&amp;#039; twice to skip creating a passphrase (for the sake of this lab environment).&lt;br /&gt;
&lt;br /&gt;
This generated two files: a private key (never share this!) and a public key.&lt;br /&gt;
&lt;br /&gt;
=== 2. Add the Public Key to GitLab ===&lt;br /&gt;
Display your public key in the terminal and copy the output exactly:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Log into your university GitLab account in your browser.&lt;br /&gt;
* Click your profile avatar (top right) -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Edit profile&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;SSH Keys&amp;#039;&amp;#039;&amp;#039; (on the left sidebar).&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Add new key&amp;#039;&amp;#039;&amp;#039;. Paste your copied key into the &amp;quot;Key&amp;quot; box. Title it &amp;quot;My Lab Laptop&amp;quot; and click &amp;#039;&amp;#039;&amp;#039;Add key&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
== Part 2: Setting Up the Remote (GitLab) ==&lt;br /&gt;
Before we write code, we document our work.&lt;br /&gt;
&lt;br /&gt;
=== 1. Create a New Repository ===&lt;br /&gt;
* Go to the GitLab homepage. Click &amp;#039;&amp;#039;&amp;#039;New Project&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Create blank project&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Project Name:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;sdpt-rfid-access&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Visibility Level:&amp;#039;&amp;#039;&amp;#039; Private (or Internal).&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Important:&amp;#039;&amp;#039;&amp;#039; Uncheck &amp;quot;Initialize repository with a README&amp;quot;. We want an entirely empty repository.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Create project&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
=== 2. Create Your First Issue ===&lt;br /&gt;
* On the left sidebar of your new project, navigate to &amp;#039;&amp;#039;&amp;#039;Plan&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Issues&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;New issue&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Title:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;Create initial RFID reader driver skeleton&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Description:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;Need a basic main.cpp file that will eventually hold the SPI communication logic for the RFID module.&amp;lt;/code&amp;gt;&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Create issue&amp;#039;&amp;#039;&amp;#039;. Take note of the &amp;#039;&amp;#039;&amp;#039;Issue Number&amp;#039;&amp;#039;&amp;#039; (e.g., &amp;lt;code&amp;gt;#1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Part 3: Initializing the Local Environment ==&lt;br /&gt;
=== 1. Configure Your Identity ===&lt;br /&gt;
Git embeds your name and email into every commit permanently. Run these once:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git config --global user.name &amp;quot;Your First and Last Name&amp;quot;&lt;br /&gt;
git config --global user.email &amp;quot;your.university.email@domain.edu&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Create Your Local Workspace ===&lt;br /&gt;
Create a folder for your project and initialize it as a Git repository.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir sdpt-rfid-access&lt;br /&gt;
cd sdpt-rfid-access&lt;br /&gt;
git init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 4: Ignoring the Noise (.gitignore) ==&lt;br /&gt;
In C/C++, compiling creates binary files (like &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.out&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;.exe&amp;lt;/code&amp;gt;). We &amp;#039;&amp;#039;&amp;#039;never&amp;#039;&amp;#039;&amp;#039; track compiled binaries in Git—we only track human-readable source code!&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s tell Git to permanently ignore build files.&lt;br /&gt;
Create a file named exactly &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch .gitignore&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open it in your editor and add these lines:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Ignore compiled binaries&lt;br /&gt;
*.o&lt;br /&gt;
*.out&lt;br /&gt;
*.exe&lt;br /&gt;
# Ignore IDE folders&lt;br /&gt;
.vscode/&lt;br /&gt;
.idea/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save the file. Let&amp;#039;s stage and commit our configuration:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add .gitignore&lt;br /&gt;
git commit -m &amp;quot;Add .gitignore for C++ project&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 5: The Three States in Practice ==&lt;br /&gt;
Let&amp;#039;s move our actual source code through the Working Directory, Staging Area, and Repository. &lt;br /&gt;
&lt;br /&gt;
=== 1. The Working Directory ===&lt;br /&gt;
Create your C++ file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch main.cpp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and add a basic skeleton:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;RFID Access Control System Initialized&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check your radar:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Notice &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; is red. It is Untracked.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 2. The Staging Area (Index) ===&lt;br /&gt;
Tell Git to include this in the next snapshot.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;It is now green. It is Staged.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 3. Time Travel and Diffs ===&lt;br /&gt;
Wait! Before committing, what exactly did we just stage? It&amp;#039;s good practice to review your code.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff --staged&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This shows you the exact lines of C++ you are about to commit. Press &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; to exit the diff view if it pauses.&lt;br /&gt;
&lt;br /&gt;
=== 4. The Repository (Commit) ===&lt;br /&gt;
Save the snapshot permanently.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git commit -m &amp;quot;Add initial RFID system skeleton&amp;quot;&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 6: Connecting Local to Remote and Closing Issues ==&lt;br /&gt;
Your code is safe locally, but the &amp;quot;Bus Factor&amp;quot; is still 1. We must push to GitLab using the SSH key we created earlier.&lt;br /&gt;
&lt;br /&gt;
=== 1. Link the Remote Server ===&lt;br /&gt;
Go back to your GitLab project page. Under &amp;quot;Push an existing Git repository&amp;quot;, click the &amp;#039;&amp;#039;&amp;#039;SSH&amp;#039;&amp;#039;&amp;#039; button (not HTTPS) and copy the &amp;lt;code&amp;gt;git remote add origin...&amp;lt;/code&amp;gt; command. It will look like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git remote add origin git@gitlab.com:your-username/sdpt-rfid-access.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Paste and run that in your terminal.&lt;br /&gt;
&lt;br /&gt;
=== 2. Push and Close the Issue ===&lt;br /&gt;
Let&amp;#039;s make one final change to fulfill our Issue requirement and close it automatically.&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and add a comment:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// TODO: Implement SPI communication with RC522 module&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stage and commit this change, using the special keyword (&amp;lt;code&amp;gt;Closes #1&amp;lt;/code&amp;gt;) in your commit message:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Add SPI TODO comment. Closes #1&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Push your local graph to the remote server:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;(Note: If Git complains about &amp;#039;main&amp;#039;, try &amp;lt;code&amp;gt;git push -u origin master&amp;lt;/code&amp;gt;, or ask your professor how to rename your default branch).&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
When prompted &amp;quot;Are you sure you want to continue connecting?&amp;quot;, type &amp;lt;code&amp;gt;yes&amp;lt;/code&amp;gt; and press Enter.&lt;br /&gt;
&lt;br /&gt;
=== 3. Verify the Magic ===&lt;br /&gt;
Refresh your GitLab project page in your browser:&lt;br /&gt;
* Your &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt; files are visible!&lt;br /&gt;
* Go to &amp;#039;&amp;#039;&amp;#039;Plan&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Issues&amp;#039;&amp;#039;&amp;#039;. Notice that Issue #1 is now automatically marked as &amp;#039;&amp;#039;&amp;#039;Closed&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
== Lab Deliverable ==&lt;br /&gt;
To receive full credit for this week&amp;#039;s lab, call the professor or teaching assistant over to your workstation and demonstrate:&lt;br /&gt;
# Your GitLab repository showing the code and the &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt; file.&lt;br /&gt;
# Your GitLab Issue board showing Issue #1 as Closed.&lt;br /&gt;
# Your terminal showing the output of the &amp;lt;code&amp;gt;git log --oneline&amp;lt;/code&amp;gt; command, displaying your three commits.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_1&amp;diff=8269</id>
		<title>SDPT Lab 1</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_1&amp;diff=8269"/>
		<updated>2026-02-23T00:40:39Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 1: Foundation of Process - Git and GitLab Basics =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Welcome to the first lab of Software Development Process and Testing (SDPT). In our lecture, we discussed why treating software like a physical breadboard leads to failure in complex systems. We introduced the Software Development Life Cycle (SDLC), Issue Tracking, and the underlying graph model of Git.&lt;br /&gt;
&lt;br /&gt;
Today, we put theory into practice. By the end of this 2-hour lab, you will have:&lt;br /&gt;
# Configured secure SSH authentication with your GitLab server.&lt;br /&gt;
# Created a project repository and your first tracked Issue.&lt;br /&gt;
# Configured Git on your local machine.&lt;br /&gt;
# Moved a C++ source file through the Three States of Git.&lt;br /&gt;
# Prevented binary files from entering your repository using &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Pushed your local history to the remote GitLab server to automatically close your Issue.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Note:&amp;#039;&amp;#039;&amp;#039; Do not rush. The goal is to understand &amp;#039;&amp;#039;where&amp;#039;&amp;#039; your files are in the Git graph at any given moment. Run &amp;lt;code&amp;gt;git status&amp;lt;/code&amp;gt; frequently!&lt;br /&gt;
&lt;br /&gt;
== Part 1: Secure Authentication (SSH Keys) ==&lt;br /&gt;
Modern code repositories do not allow you to push code using your standard web password. We must set up a secure cryptographic key pair. &lt;br /&gt;
&lt;br /&gt;
=== 1. Generate an SSH Key Pair ===&lt;br /&gt;
Open your terminal (Linux/macOS) or Git Bash (Windows) and type:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;your.university.email@domain.edu&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Press &amp;#039;&amp;#039;&amp;#039;Enter&amp;#039;&amp;#039;&amp;#039; to accept the default file location.&lt;br /&gt;
* Press &amp;#039;&amp;#039;&amp;#039;Enter&amp;#039;&amp;#039;&amp;#039; twice to skip creating a passphrase (for the sake of this lab environment).&lt;br /&gt;
&lt;br /&gt;
This generated two files: a private key (never share this!) and a public key.&lt;br /&gt;
&lt;br /&gt;
=== 2. Add the Public Key to GitLab ===&lt;br /&gt;
Display your public key in the terminal and copy the output exactly:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Log into your university GitLab account in your browser.&lt;br /&gt;
* Click your profile avatar (top right) -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Edit profile&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;SSH Keys&amp;#039;&amp;#039;&amp;#039; (on the left sidebar).&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Add new key&amp;#039;&amp;#039;&amp;#039;. Paste your copied key into the &amp;quot;Key&amp;quot; box. Title it &amp;quot;My Lab Laptop&amp;quot; and click &amp;#039;&amp;#039;&amp;#039;Add key&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
== Part 2: Setting Up the Remote (GitLab) ==&lt;br /&gt;
Before we write code, we document our work.&lt;br /&gt;
&lt;br /&gt;
=== 1. Create a New Repository ===&lt;br /&gt;
* Go to the GitLab homepage. Click &amp;#039;&amp;#039;&amp;#039;New Project&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Create blank project&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Project Name:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;sdpt-rfid-access&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Visibility Level:&amp;#039;&amp;#039;&amp;#039; Private (or Internal).&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Important:&amp;#039;&amp;#039;&amp;#039; Uncheck &amp;quot;Initialize repository with a README&amp;quot;. We want an entirely empty repository.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Create project&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
=== 2. Create Your First Issue ===&lt;br /&gt;
* On the left sidebar of your new project, navigate to &amp;#039;&amp;#039;&amp;#039;Plan&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Issues&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;New issue&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Title:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;Create initial RFID reader driver skeleton&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Description:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;Need a basic main.cpp file that will eventually hold the SPI communication logic for the RFID module.&amp;lt;/code&amp;gt;&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Create issue&amp;#039;&amp;#039;&amp;#039;. Take note of the &amp;#039;&amp;#039;&amp;#039;Issue Number&amp;#039;&amp;#039;&amp;#039; (e.g., &amp;lt;code&amp;gt;#1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Part 3: Initializing the Local Environment ==&lt;br /&gt;
=== 1. Configure Your Identity ===&lt;br /&gt;
Git embeds your name and email into every commit permanently. Run these once:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git config --global user.name &amp;quot;Your First and Last Name&amp;quot;&lt;br /&gt;
git config --global user.email &amp;quot;your.university.email@domain.edu&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Create Your Local Workspace ===&lt;br /&gt;
Create a folder for your project and initialize it as a Git repository.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir sdpt-rfid-access&lt;br /&gt;
cd sdpt-rfid-access&lt;br /&gt;
git init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 4: Ignoring the Noise (.gitignore) ==&lt;br /&gt;
In C/C++, compiling creates binary files (like &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.out&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;.exe&amp;lt;/code&amp;gt;). We &amp;#039;&amp;#039;&amp;#039;never&amp;#039;&amp;#039;&amp;#039; track compiled binaries in Git—we only track human-readable source code!&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s tell Git to permanently ignore build files.&lt;br /&gt;
Create a file named exactly &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch .gitignore&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open it in your editor and add these lines:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Ignore compiled binaries&lt;br /&gt;
*.o&lt;br /&gt;
*.out&lt;br /&gt;
*.exe&lt;br /&gt;
# Ignore IDE folders&lt;br /&gt;
.vscode/&lt;br /&gt;
.idea/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save the file. Let&amp;#039;s stage and commit our configuration:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add .gitignore&lt;br /&gt;
git commit -m &amp;quot;Add .gitignore for C++ project&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 5: The Three States in Practice ==&lt;br /&gt;
Let&amp;#039;s move our actual source code through the Working Directory, Staging Area, and Repository. &lt;br /&gt;
&lt;br /&gt;
=== 1. The Working Directory ===&lt;br /&gt;
Create your C++ file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch main.cpp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and add a basic skeleton:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;RFID Access Control System Initialized&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check your radar:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Notice &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; is red. It is Untracked.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 2. The Staging Area (Index) ===&lt;br /&gt;
Tell Git to include this in the next snapshot.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;It is now green. It is Staged.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 3. Time Travel and Diffs ===&lt;br /&gt;
Wait! Before committing, what exactly did we just stage? It&amp;#039;s good practice to review your code.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff --staged&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This shows you the exact lines of C++ you are about to commit. Press &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; to exit the diff view if it pauses.&lt;br /&gt;
&lt;br /&gt;
=== 4. The Repository (Commit) ===&lt;br /&gt;
Save the snapshot permanently.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git commit -m &amp;quot;Add initial RFID system skeleton&amp;quot;&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 6: Connecting Local to Remote and Closing Issues ==&lt;br /&gt;
Your code is safe locally, but the &amp;quot;Bus Factor&amp;quot; is still 1. We must push to GitLab using the SSH key we created earlier.&lt;br /&gt;
&lt;br /&gt;
=== 1. Link the Remote Server ===&lt;br /&gt;
Go back to your GitLab project page. Under &amp;quot;Push an existing Git repository&amp;quot;, click the &amp;#039;&amp;#039;&amp;#039;SSH&amp;#039;&amp;#039;&amp;#039; button (not HTTPS) and copy the &amp;lt;code&amp;gt;git remote add origin...&amp;lt;/code&amp;gt; command. It will look like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git remote add origin git@gitlab.com:your-username/sdpt-rfid-access.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Paste and run that in your terminal.&lt;br /&gt;
&lt;br /&gt;
=== 2. Push and Close the Issue ===&lt;br /&gt;
Let&amp;#039;s make one final change to fulfill our Issue requirement and close it automatically.&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and add a comment:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// TODO: Implement SPI communication with RC522 module&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stage and commit this change, using the special keyword (&amp;lt;code&amp;gt;Closes #1&amp;lt;/code&amp;gt;) in your commit message:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Add SPI TODO comment. Closes #1&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Push your local graph to the remote server:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;(Note: If Git complains about &amp;#039;main&amp;#039;, try &amp;lt;code&amp;gt;git push -u origin master&amp;lt;/code&amp;gt;, or ask your professor how to rename your default branch).&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
When prompted &amp;quot;Are you sure you want to continue connecting?&amp;quot;, type &amp;lt;code&amp;gt;yes&amp;lt;/code&amp;gt; and press Enter.&lt;br /&gt;
&lt;br /&gt;
=== 3. Verify the Magic ===&lt;br /&gt;
Refresh your GitLab project page in your browser:&lt;br /&gt;
* Your &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt; files are visible!&lt;br /&gt;
* Go to &amp;#039;&amp;#039;&amp;#039;Plan&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Issues&amp;#039;&amp;#039;&amp;#039;. Notice that Issue #1 is now automatically marked as &amp;#039;&amp;#039;&amp;#039;Closed&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
== Lab Deliverable ==&lt;br /&gt;
To receive full credit for this week&amp;#039;s lab, call the professor or teaching assistant over to your workstation and demonstrate:&lt;br /&gt;
# Your GitLab repository showing the code and the &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt; file.&lt;br /&gt;
# Your GitLab Issue board showing Issue #1 as Closed.&lt;br /&gt;
# Your terminal showing the output of the &amp;lt;code&amp;gt;git log --oneline&amp;lt;/code&amp;gt; command, displaying your three commits.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_1&amp;diff=8268</id>
		<title>SDPT Lab 1</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_1&amp;diff=8268"/>
		<updated>2026-02-23T00:39:55Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 1: Foundation of Process - Git and GitLab Basics =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Welcome to the first lab of Software Development Process and Testing (SDPT). In our lecture, we discussed why treating software like a physical breadboard leads to failure in complex systems. We introduced the Software Development Life Cycle (SDLC), Issue Tracking, and the underlying graph model of Git.&lt;br /&gt;
&lt;br /&gt;
Today, we put theory into practice. By the end of this 2-hour lab, you will have:&lt;br /&gt;
# Configured secure SSH authentication with your GitLab server.&lt;br /&gt;
# Created a project repository and your first tracked Issue.&lt;br /&gt;
# Configured Git on your local machine.&lt;br /&gt;
# Moved a C++ source file through the Three States of Git.&lt;br /&gt;
# Prevented binary files from entering your repository using &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Pushed your local history to the remote GitLab server to automatically close your Issue.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Note:&amp;#039;&amp;#039;&amp;#039; Do not rush. The goal is to understand &amp;#039;&amp;#039;where&amp;#039;&amp;#039; your files are in the Git graph at any given moment. Run &amp;lt;code&amp;gt;git status&amp;lt;/code&amp;gt; frequently!&lt;br /&gt;
&lt;br /&gt;
== Part 1: Secure Authentication (SSH Keys) ==&lt;br /&gt;
Modern code repositories do not allow you to push code using your standard web password. We must set up a secure cryptographic key pair. &lt;br /&gt;
&lt;br /&gt;
=== 1. Generate an SSH Key Pair ===&lt;br /&gt;
Open your terminal (Linux/macOS) or Git Bash (Windows) and type:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;your.university.email@domain.edu&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Press &amp;#039;&amp;#039;&amp;#039;Enter&amp;#039;&amp;#039;&amp;#039; to accept the default file location.&lt;br /&gt;
* Press &amp;#039;&amp;#039;&amp;#039;Enter&amp;#039;&amp;#039;&amp;#039; twice to skip creating a passphrase (for the sake of this lab environment).&lt;br /&gt;
&lt;br /&gt;
This generated two files: a private key (never share this!) and a public key.&lt;br /&gt;
&lt;br /&gt;
=== 2. Add the Public Key to GitLab ===&lt;br /&gt;
Display your public key in the terminal and copy the output exactly:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Log into your university GitLab account in your browser.&lt;br /&gt;
* Click your profile avatar (top right) -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Edit profile&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;SSH Keys&amp;#039;&amp;#039;&amp;#039; (on the left sidebar).&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Add new key&amp;#039;&amp;#039;&amp;#039;. Paste your copied key into the &amp;quot;Key&amp;quot; box. Title it &amp;quot;My Lab Laptop&amp;quot; and click &amp;#039;&amp;#039;&amp;#039;Add key&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
== Part 2: Setting Up the Remote (GitLab) ==&lt;br /&gt;
Before we write code, we document our work.&lt;br /&gt;
&lt;br /&gt;
=== 1. Create a New Repository ===&lt;br /&gt;
* Go to the GitLab homepage. Click &amp;#039;&amp;#039;&amp;#039;New Project&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Create blank project&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Project Name:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;sdpt-rfid-access&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Visibility Level:&amp;#039;&amp;#039;&amp;#039; Private (or Internal).&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Important:&amp;#039;&amp;#039;&amp;#039; Uncheck &amp;quot;Initialize repository with a README&amp;quot;. We want an entirely empty repository.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Create project&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
=== 2. Create Your First Issue ===&lt;br /&gt;
* On the left sidebar of your new project, navigate to &amp;#039;&amp;#039;&amp;#039;Plan&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Issues&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;New issue&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Title:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;Create initial RFID reader driver skeleton&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Description:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;Need a basic main.cpp file that will eventually hold the SPI communication logic for the RFID module.&amp;lt;/code&amp;gt;&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Create issue&amp;#039;&amp;#039;&amp;#039;. Take note of the &amp;#039;&amp;#039;&amp;#039;Issue Number&amp;#039;&amp;#039;&amp;#039; (e.g., &amp;lt;code&amp;gt;#1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Part 3: Initializing the Local Environment ==&lt;br /&gt;
=== 1. Configure Your Identity ===&lt;br /&gt;
Git embeds your name and email into every commit permanently. Run these once:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git config --global user.name &amp;quot;Your First and Last Name&amp;quot;&lt;br /&gt;
git config --global user.email &amp;quot;your.university.email@domain.edu&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Create Your Local Workspace ===&lt;br /&gt;
Create a folder for your project and initialize it as a Git repository.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir sdpt-rfid-access&lt;br /&gt;
cd sdpt-rfid-access&lt;br /&gt;
git init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 4: Ignoring the Noise (.gitignore) ==&lt;br /&gt;
In C/C++, compiling creates binary files (like &amp;lt;code&amp;gt;.o&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.out&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;.exe&amp;lt;/code&amp;gt;). We &amp;#039;&amp;#039;&amp;#039;never&amp;#039;&amp;#039;&amp;#039; track compiled binaries in Git—we only track human-readable source code!&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s tell Git to permanently ignore build files.&lt;br /&gt;
Create a file named exactly &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch .gitignore&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open it in your editor and add these lines:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Ignore compiled binaries&lt;br /&gt;
*.o&lt;br /&gt;
*.out&lt;br /&gt;
*.exe&lt;br /&gt;
# Ignore IDE folders&lt;br /&gt;
.vscode/&lt;br /&gt;
.idea/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save the file. Let&amp;#039;s stage and commit our configuration:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add .gitignore&lt;br /&gt;
git commit -m &amp;quot;Add .gitignore for C++ project&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 5: The Three States in Practice ==&lt;br /&gt;
Let&amp;#039;s move our actual source code through the Working Directory, Staging Area, and Repository. &lt;br /&gt;
&lt;br /&gt;
=== 1. The Working Directory ===&lt;br /&gt;
Create your C++ file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch main.cpp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and add a basic skeleton:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;RFID Access Control System Initialized&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check your radar:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Notice &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; is red. It is Untracked.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 2. The Staging Area (Index) ===&lt;br /&gt;
Tell Git to include this in the next snapshot.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;It is now green. It is Staged.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 3. Time Travel and Diffs ===&lt;br /&gt;
Wait! Before committing, what exactly did we just stage? It&amp;#039;s good practice to review your code.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff --staged&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This shows you the exact lines of C++ you are about to commit. Press &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; to exit the diff view if it pauses.&lt;br /&gt;
&lt;br /&gt;
=== 4. The Repository (Commit) ===&lt;br /&gt;
Save the snapshot permanently.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git commit -m &amp;quot;Add initial RFID system skeleton&amp;quot;&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 6: Connecting Local to Remote and Closing Issues ==&lt;br /&gt;
Your code is safe locally, but the &amp;quot;Bus Factor&amp;quot; is still 1. We must push to GitLab using the SSH key we created earlier.&lt;br /&gt;
&lt;br /&gt;
=== 1. Link the Remote Server ===&lt;br /&gt;
Go back to your GitLab project page. Under &amp;quot;Push an existing Git repository&amp;quot;, click the &amp;#039;&amp;#039;&amp;#039;SSH&amp;#039;&amp;#039;&amp;#039; button (not HTTPS) and copy the &amp;lt;code&amp;gt;git remote add origin...&amp;lt;/code&amp;gt; command. It will look like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git remote add origin git@gitlab.com:your-username/sdpt-rfid-access.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Paste and run that in your terminal.&lt;br /&gt;
&lt;br /&gt;
=== 2. Push and Close the Issue ===&lt;br /&gt;
Let&amp;#039;s make one final change to fulfill our Issue requirement and close it automatically.&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and add a comment:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// TODO: Implement SPI communication with RC522 module&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stage and commit this change, using the special keyword (&amp;lt;code&amp;gt;Closes #1&amp;lt;/code&amp;gt;) in your commit message:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Add SPI TODO comment. Closes #1&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Push your local graph to the remote server:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;(Note: If Git complains about &amp;#039;main&amp;#039;, try &amp;lt;code&amp;gt;git push -u origin master&amp;lt;/code&amp;gt;, or ask your professor how to rename your default branch).&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
When prompted &amp;quot;Are you sure you want to continue connecting?&amp;quot;, type &amp;lt;code&amp;gt;yes&amp;lt;/code&amp;gt; and press Enter.&lt;br /&gt;
&lt;br /&gt;
=== 3. Verify the Magic ===&lt;br /&gt;
Refresh your GitLab project page in your browser:&lt;br /&gt;
* Your &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt; files are visible!&lt;br /&gt;
* Go to &amp;#039;&amp;#039;&amp;#039;Plan&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Issues&amp;#039;&amp;#039;&amp;#039;. Notice that Issue #1 is now automatically marked as &amp;#039;&amp;#039;&amp;#039;Closed&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Lab Deliverable ==&lt;br /&gt;
To receive full credit for this week&amp;#039;s lab, call the professor or teaching assistant over to your workstation and demonstrate:&lt;br /&gt;
# Your GitLab repository showing the code and the &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt; file.&lt;br /&gt;
# Your GitLab Issue board showing Issue #1 as Closed.&lt;br /&gt;
# Your terminal showing the output of the &amp;lt;code&amp;gt;git log --oneline&amp;lt;/code&amp;gt; command, displaying your three commits.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_1&amp;diff=8267</id>
		<title>SDPT Lab 1</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDPT_Lab_1&amp;diff=8267"/>
		<updated>2026-02-23T00:34:29Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: = Lab 1: Foundation of Process - Git and GitLab Basics =  == Introduction == Welcome to the first lab of Software Development Process and Testing (SDPT). In our lecture, we discuss...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lab 1: Foundation of Process - Git and GitLab Basics =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Welcome to the first lab of Software Development Process and Testing (SDPT). In our lecture, we discussed why treating software like a physical breadboard leads to failure in complex systems. We introduced the Software Development Life Cycle (SDLC), Issue Tracking, and the underlying graph model of Git.&lt;br /&gt;
&lt;br /&gt;
Today, we put theory into practice. By the end of this 2-hour lab, you will have:&lt;br /&gt;
# Created a project repository on GitLab.&lt;br /&gt;
# Created your first tracked Issue.&lt;br /&gt;
# Configured Git on your local machine.&lt;br /&gt;
# Moved a C++ source file through the Three States of Git.&lt;br /&gt;
# Pushed your local history to the remote GitLab server and automatically closed your Issue.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Note:&amp;#039;&amp;#039;&amp;#039; Do not rush. The goal is to understand &amp;#039;&amp;#039;where&amp;#039;&amp;#039; your files are in the Git graph at any given moment. Run &amp;lt;code&amp;gt;git status&amp;lt;/code&amp;gt; frequently!&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 1: Setting Up the Remote (GitLab) ==&lt;br /&gt;
Before we touch the terminal, we need to set up our remote infrastructure and document the work we intend to do.&lt;br /&gt;
&lt;br /&gt;
=== 1. Create a New Repository ===&lt;br /&gt;
* Log into your university GitLab account.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;New Project&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Create blank project&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Project Name:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;sdpt-rfid-access&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Visibility Level:&amp;#039;&amp;#039;&amp;#039; Private (or Internal, depending on your professor&amp;#039;s instructions).&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Important:&amp;#039;&amp;#039;&amp;#039; Uncheck &amp;quot;Initialize repository with a README&amp;quot;. We want an entirely empty repository to practice pushing from our local machine.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Create project&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
=== 2. Create Your First Issue ===&lt;br /&gt;
We need a business requirement before we write code. &lt;br /&gt;
* On the left sidebar of your new project, navigate to &amp;#039;&amp;#039;&amp;#039;Plan&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Issues&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;New issue&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Title:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;Create initial RFID reader driver skeleton&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Description:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;Need a basic main.cpp file that will eventually hold the SPI communication logic for the RFID module.&amp;lt;/code&amp;gt;&lt;br /&gt;
* Click &amp;#039;&amp;#039;&amp;#039;Create issue&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Take note of the &amp;#039;&amp;#039;&amp;#039;Issue Number&amp;#039;&amp;#039;&amp;#039; (e.g., &amp;lt;code&amp;gt;#1&amp;lt;/code&amp;gt;) generated next to the title. You will need this later!&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 2: Initializing the Local Environment ==&lt;br /&gt;
Now, open your terminal (Linux/macOS) or Git Bash (Windows). &lt;br /&gt;
&lt;br /&gt;
=== 1. Configure Your Identity ===&lt;br /&gt;
Git embeds the author&amp;#039;s name and email into every commit permanently. You only need to run these commands once per computer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git config --global user.name &amp;quot;Your First and Last Name&amp;quot;&lt;br /&gt;
git config --global user.email &amp;quot;your.university.email@domain.edu&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Create Your Local Workspace ===&lt;br /&gt;
Create a folder for your project and initialize it as a Git repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir sdpt-rfid-access&lt;br /&gt;
cd sdpt-rfid-access&lt;br /&gt;
git init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice the output: &amp;lt;code&amp;gt;Initialized empty Git repository&amp;lt;/code&amp;gt;. A hidden &amp;lt;code&amp;gt;.git&amp;lt;/code&amp;gt; folder has been created. This is your database.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 3: The Three States in Practice ==&lt;br /&gt;
Remember the three states from the lecture: Working Directory, Staging Area, and Repository. Let&amp;#039;s move a file through them. &lt;br /&gt;
&lt;br /&gt;
=== 1. The Working Directory ===&lt;br /&gt;
Create a new C++ file. This represents writing your initial code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch main.cpp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; in your favorite text editor (nano, vim, VS Code) and add a basic skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;RFID Access Control System Initialized&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, check your radar:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Notice that &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; is red and listed under &amp;quot;Untracked files&amp;quot;. Git sees the file in your Working Directory, but is not managing it yet.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 2. The Staging Area (Index) ===&lt;br /&gt;
Tell Git you want to include this file in your next commit snapshot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Notice the file is now green and under &amp;quot;Changes to be committed&amp;quot;. It is in the Staging Area.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 3. The Repository (Commit) ===&lt;br /&gt;
Save the snapshot permanently into your local Git database.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git commit -m &amp;quot;Add initial RFID system skeleton&amp;quot;&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Your working tree is now clean. The snapshot is stored as a node in your local Git graph.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Part 4: Connecting Local to Remote and Closing Issues ==&lt;br /&gt;
Your code is safe locally, but the &amp;quot;Bus Factor&amp;quot; is still 1. If your laptop crashes, the code is gone. We must push to GitLab.&lt;br /&gt;
&lt;br /&gt;
=== 1. Link the Remote Server ===&lt;br /&gt;
Go back to your GitLab project page. Under &amp;quot;Push an existing Git repository&amp;quot;, copy the &amp;lt;code&amp;gt;git remote add origin...&amp;lt;/code&amp;gt; command. It will look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git remote add origin https://gitlab.com/your-username/sdpt-rfid-access.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Push and Close the Issue ===&lt;br /&gt;
We want to push our code AND tell GitLab that this code fulfills the requirement we documented in Part 1. We do this by making a new commit that references the Issue number.&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s make a small change to &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt;. Open it and add a comment:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// TODO: Implement SPI communication with RC522 module&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, stage and commit this change, using a special keyword (&amp;lt;code&amp;gt;Closes #1&amp;lt;/code&amp;gt;) in the commit message:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add main.cpp&lt;br /&gt;
git commit -m &amp;quot;Add SPI TODO comment. Closes #1&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, push your local graph to the remote server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git push -u origin main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;(Note: If your default branch is &amp;#039;master&amp;#039; instead of &amp;#039;main&amp;#039;, use &amp;lt;code&amp;gt;git push -u origin master&amp;lt;/code&amp;gt;)&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== 3. Verify the Magic ===&lt;br /&gt;
Go back to your browser and refresh your GitLab project page:&lt;br /&gt;
* Your &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; file is now visible on the server!&lt;br /&gt;
* Go to &amp;#039;&amp;#039;&amp;#039;Plan&amp;#039;&amp;#039;&amp;#039; -&amp;gt; &amp;#039;&amp;#039;&amp;#039;Issues&amp;#039;&amp;#039;&amp;#039;. Notice that Issue #1 is now automatically marked as &amp;#039;&amp;#039;&amp;#039;Closed&amp;#039;&amp;#039;&amp;#039;. Git and GitLab worked together to link your code directly to the business requirement.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Lab Deliverable ==&lt;br /&gt;
To receive full credit for this week&amp;#039;s lab, call the professor or teaching assistant over to your workstation and demonstrate:&lt;br /&gt;
# Your GitLab repository showing the &amp;lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; file.&lt;br /&gt;
# Your GitLab Issue board showing Issue #1 as Closed.&lt;br /&gt;
# Your terminal showing the output of the &amp;lt;code&amp;gt;git log&amp;lt;/code&amp;gt; command, displaying your two commits.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8266</id>
		<title>Software Development Process and Testing</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Software_Development_Process_and_Testing&amp;diff=8266"/>
		<updated>2026-02-23T00:34:18Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: * SDPT Lab 1&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[SDPT Lab 1]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Main_Page&amp;diff=8265</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Main_Page&amp;diff=8265"/>
		<updated>2026-02-23T00:33:36Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The purpose of this page is the index the lab tutorials and tasks, as well as the auxiliary resources for the lectures and laboratories taught within the DCAE department.&lt;br /&gt;
&lt;br /&gt;
== Course List ==&lt;br /&gt;
&lt;br /&gt;
* [[Integrated Digital Circuits (lecture)]]&lt;br /&gt;
* [[Data Structures and Algorithms]]&lt;br /&gt;
* [[Power Semiconductor Devices]]&lt;br /&gt;
&lt;br /&gt;
== Laboratories List ==&lt;br /&gt;
* [[Advanced Digital Systems]]&lt;br /&gt;
* [[Data Structures and Algorithms (lab)]]&lt;br /&gt;
* [[Digital Integrated Circuits (lab)|Digital Integrated Circuits]]&lt;br /&gt;
* [[Digital Integrated Circuits (old lab)|Digital Integrated Circuits - old]]&lt;br /&gt;
* [[Object Oriented Programming]]&lt;br /&gt;
* [[Power Semiconductor Devices (lab)]]&lt;br /&gt;
* [https://users.dcae.pub.ro/~zhascsi/courses/dsd/dsd.html Digital Systems Design Project]&lt;br /&gt;
* [[Electronic Devices(lab)]]&lt;br /&gt;
* [[Electronic Circuits(lab)]]&lt;br /&gt;
* [[Software Development Process and Resting]]&lt;br /&gt;
&lt;br /&gt;
== Seminaries List ==&lt;br /&gt;
* [[Digital Integrated Circuits (sem)|Digital Integrated Circuits]]&lt;br /&gt;
&lt;br /&gt;
== Applications List ==&lt;br /&gt;
* [[Digital Integrated Circuits (app)|Digital Integrated Circuits]]&lt;br /&gt;
&lt;br /&gt;
== Project List ==&lt;br /&gt;
* [[Project 1 - Electronic Devices and Circuits |Electronic Devices and Circuits (Project 1)]]&lt;br /&gt;
&lt;br /&gt;
* [[Project Master |Project Master]]&lt;br /&gt;
&lt;br /&gt;
== Evaluation Forms ==&lt;br /&gt;
* [[Evaluation Forms 2014-2015, Semester I]]&lt;br /&gt;
* [[Evaluation Forms 2014-2015, Semester II]]&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=SDA_Lucrarea_1&amp;diff=7751</id>
		<title>SDA Lucrarea 1</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=SDA_Lucrarea_1&amp;diff=7751"/>
		<updated>2024-09-29T18:47:58Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;După acest laborator veți putea folosi IDE-ul Netbeans pentru a scrie și depana programe în C. Totodată veți relua și recapitula noțiunile legate de pointeri în C.&lt;br /&gt;
&lt;br /&gt;
= Utilizarea IDE-ului CLion =&lt;br /&gt;
&lt;br /&gt;
[https://www.jetbrains.com/clion CLion] este un mediu integrat de dezvoltare (IDE) care permite dezvoltarea de programe în limbajele C și C++. CLion nu instalează și compilator pentru C/C++, acesta trebuie instalat manual, în prealabil. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: red; font-weight: bold&amp;quot;&amp;gt;Atenție:&amp;lt;/span&amp;gt; Imaginea de Linux folosită la Programarea Calculatoarelor are deja instalat compilatorul de C.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Instalarea GCC ==&lt;br /&gt;
&lt;br /&gt;
=== Instalarea GCC în Linux ===&lt;br /&gt;
&lt;br /&gt;
Pentru instalarea compilatorului de C (GCC) în distribuțiile de Linux provenite din Ubuntu (Ubuntu, Kubuntu, Xubuntu, Mint, LMDE, etc.) se poate folosi comanda:&lt;br /&gt;
&lt;br /&gt;
 apt-get install -y build-essential&lt;br /&gt;
&lt;br /&gt;
=== Instalarea GCC în Windows ===&lt;br /&gt;
&lt;br /&gt;
Pentru compilarea de programe cu GCC în Windows, aveți nevoie de instalarea acestui compilator care poate fi făcută prin instalarea unuia din următoarele două suite de programe:&lt;br /&gt;
* [https://cygwin.com Cygwin] - Tutorial de instalare [https://cygwin.com/install.html aici].&lt;br /&gt;
* [http://www.mingw.org/ MinGW] - Tutorial de instalare [http://www.mingw.org/wiki/InstallationHOWTOforMinGW aici].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: red; font-weight: bold&amp;quot;&amp;gt;Atenție:&amp;lt;/span&amp;gt; Nu uitați ca la instalare să bifați în lista de pachete și compilatorul de C (&amp;lt;code&amp;gt;gcc&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; și &amp;lt;code&amp;gt;git&amp;lt;/code&amp;gt;.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Instalarea CLion ==&lt;br /&gt;
&lt;br /&gt;
De la adresa https://www.jetbrains.com/clion/download/#section=linux puteți descărca kitul de instalare pentru sistemul vostru de operare.&lt;br /&gt;
După instalare, urmaţi următorii paşi de configurare, în funcţie de suita de programe aleasă:&lt;br /&gt;
* [https://www.jetbrains.com/help/clion/quick-tutorial-on-configuring-clion-on-windows.html#Cygwin Configurare CLion cu Cygwin]&lt;br /&gt;
* [https://www.jetbrains.com/help/clion/quick-tutorial-on-configuring-clion-on-windows.html#MinGW  Configurare CLion cu MinGW]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Realizarea unui proiect ==&lt;br /&gt;
&lt;br /&gt;
Odată pornit, CLion oferă posibilitatea de a deschide un proiect existent, sau de a crea unul nou. Vrem să realizăm un proiect nou, aşadar se va alege &amp;#039;&amp;#039;&amp;#039;New Project&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt; &amp;#039;&amp;#039;&amp;#039; Observație: &amp;#039;&amp;#039;&amp;#039; Se poate realiza un nou proiect atunci când altul este deja deschis folosind meniul &amp;lt;code&amp;gt;File - New Project &amp;lt;/code&amp;gt; .&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fișier:Welcome_to_clion.png | 600px | Imaginea 1]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; Mai departe se va selecta categoria &amp;#039;&amp;#039;&amp;#039;C++ Executable&amp;#039;&amp;#039;&amp;#039; şi se va introduce locaţia proiectului.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: red; font-weight: bold&amp;quot;&amp;gt;Atenție:&amp;lt;/span&amp;gt; În imagine se observă că locaţia introdusă este &amp;#039;&amp;#039;&amp;#039;/home/student/projects/NewProject&amp;#039;&amp;#039;&amp;#039;. Se recomandă ca directorul în care se realizează proiectul să aibă numele proiectului, sau un nume sugestiv (în imagine &amp;#039;&amp;#039;&amp;#039;NewProject&amp;#039;&amp;#039;&amp;#039;)&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fișier:New_project_location_clion.png | 600px | Imaginea 2]]&lt;br /&gt;
&lt;br /&gt;
== Componentele IDE-ului CLion == &lt;br /&gt;
&lt;br /&gt;
[[Fișier:CLion_env.png | 1000px | Imaginea 3]]&lt;br /&gt;
&lt;br /&gt;
La crearea unui nou proiect, IDE-ul CLion generează automat fişierul &amp;#039;&amp;#039;&amp;#039;main.cpp&amp;#039;&amp;#039;&amp;#039;. Acesta conţine un exemplu program ce va fi rescris de către utilizator. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Secţiunile marcate în imagine reprezintă:&lt;br /&gt;
# Zona &amp;lt;span style=&amp;quot;color: green&amp;quot;&amp;gt;verde&amp;lt;/span&amp;gt; - &amp;#039;&amp;#039;&amp;#039;Project view&amp;#039;&amp;#039;&amp;#039; indică toate fişierele şi directoarele ce alcătuiesc proiectul.&lt;br /&gt;
# Zona &amp;lt;span style=&amp;quot;color: blue&amp;quot;&amp;gt;albastră&amp;lt;/span&amp;gt; - &amp;#039;&amp;#039;&amp;#039;Editor&amp;#039;&amp;#039;&amp;#039; este fereastra de vizualizare şi editare a textului &lt;br /&gt;
# Zona &amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;roşie&amp;lt;/span&amp;gt; - &amp;#039;&amp;#039;&amp;#039;Toolbar&amp;#039;&amp;#039;&amp;#039; oferă acces rapid pentru operaţiile uzuale. Dintre acestea, cel mai des vom folosi:&lt;br /&gt;
#*&amp;#039;&amp;#039;&amp;#039;Build&amp;#039;&amp;#039;&amp;#039; [[Fișier:CLion_build_button.png | 16px]]&lt;br /&gt;
#*&amp;#039;&amp;#039;&amp;#039;Run&amp;#039;&amp;#039;&amp;#039; [[Fișier:CLion_run_button.png | 16px]]&lt;br /&gt;
#*&amp;#039;&amp;#039;&amp;#039;Debug&amp;#039;&amp;#039;&amp;#039; [[Fișier:CLion_debug_button.png | 16px]]&lt;br /&gt;
# Zona &amp;lt;span style=&amp;quot;color: gold&amp;quot;&amp;gt;galbenă&amp;lt;/span&amp;gt; - &amp;#039;&amp;#039;&amp;#039;Run&amp;#039;&amp;#039;&amp;#039; este zona în care se introduc datele de intrare şi se în care vor fi afişate datele de ieşire.&lt;br /&gt;
&lt;br /&gt;
== Exemplu de program în modul &amp;#039;&amp;#039;debug&amp;#039;&amp;#039; ==&lt;br /&gt;
&lt;br /&gt;
Copiați codul de mai jos înlocuind programul deja existent în fișierul &amp;#039;&amp;#039;main.c&amp;#039;&amp;#039;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(){&lt;br /&gt;
    printf(&amp;quot;Debugging program...\n&amp;quot;);&lt;br /&gt;
    int value = 0;&lt;br /&gt;
    value = value + 1;&lt;br /&gt;
    value++;&lt;br /&gt;
    value = value * 2;&lt;br /&gt;
    value -= 1;&lt;br /&gt;
    printf(&amp;quot;Value is now %d!\n&amp;quot;, value);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pentru a executa programul în modul debug trebuie sa introducem cel puţin un &amp;#039;&amp;#039;&amp;#039;breakpoint&amp;#039;&amp;#039;&amp;#039;. Astfel indicăm programului unde se va opri pentru a ne acorda control asupra execuţiei, având posibilitatea de a continua execuţia pas cu pas. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Introducem un nou breakpoint dând click în dreptul liniei de la care vrem să obţinem controlul. În cazul nostru, vom alege să indroducem un breakpoint chiar la definirea variabilei &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Fișier:CLion_breakpoint.png | 1000px | Imaginea 4]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: red; font-weight: bold&amp;quot;&amp;gt;Atenție:&amp;lt;/span&amp;gt; Când alegem locaţia unui breakpoint trebuie să ţinem cont de următorul aspect: în modul &amp;#039;&amp;#039;&amp;#039;debug&amp;#039;&amp;#039;&amp;#039; programul se va opri &amp;#039;&amp;#039;&amp;#039;înainte&amp;#039;&amp;#039;&amp;#039; de a executa linia în dreptul căreia a fost introdus breakpoint-ul!&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
În continuare, trebuie se pornim execuţia programului in modul debug [[Fișier:CLion_debug_button.png | 16px]]. Observăm apariţia ferestrei Debug (chenarul albastru, Imaginea 5) ce conţine următoarele:&lt;br /&gt;
#Zona &amp;lt;span style=&amp;quot;color: gold&amp;quot;&amp;gt;galbenă&amp;lt;/span&amp;gt; - fereastra cu toate variabilele declarate, împreună cu valorile lor. Momentan nu există nicio variabilă declarată (deoarece linia asupra la care ne-am oprit nu a fost încă executată!)&lt;br /&gt;
#Zona &amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;roşie&amp;lt;/span&amp;gt; - Permite trecerea între fereastra pentru procesul de depanare (&amp;#039;&amp;#039;&amp;#039;Debugger&amp;#039;&amp;#039;&amp;#039;) şi fereastra în care se afişează/introduc datele (&amp;#039;&amp;#039;&amp;#039;Console&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
#Zona &amp;lt;span style=&amp;quot;color: green&amp;quot;&amp;gt;verde&amp;lt;/span&amp;gt; - Conţine comenzile pentru controlul execuţiei în modul debug (comenzi numite &amp;#039;&amp;#039;&amp;#039;stepping actions&amp;#039;&amp;#039;&amp;#039;):&lt;br /&gt;
#*&amp;#039;&amp;#039;&amp;#039;Step over&amp;#039;&amp;#039;&amp;#039; [[Fișier:CLion_step_over.png | 16px]] - Execută comenzile de pe linia curentă şi trece la următoarea linie&lt;br /&gt;
#*&amp;#039;&amp;#039;&amp;#039;Step into&amp;#039;&amp;#039;&amp;#039; [[Fișier:CLion_step_into.png | 16px]] - Programul va executa linia curentă iar dacă pe linia curentă există un apel de funcție, se va opri pe prima linie din funcția respectivă. Această comandă este utilă atunci cand pe linia curentă se află un apel de funcţie şi vrem sa studiem comportamentul codului din interiorul funcţiei.&lt;br /&gt;
#*&amp;#039;&amp;#039;&amp;#039;Step out&amp;#039;&amp;#039;&amp;#039; [[Fișier:CLion_step_out.png | 16px]] - Termină de executat funcţia în care se află linia curentă&lt;br /&gt;
#*&amp;#039;&amp;#039;&amp;#039;Run to cursor&amp;#039;&amp;#039;&amp;#039; [[Fișier:CLion_run_to_cursor.png | 16px]] - Execută toate instructiunile până se intâlneste cursorul.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt; &amp;#039;&amp;#039;&amp;#039; Observație: &amp;#039;&amp;#039;&amp;#039; În modul debug, linia curentă este marcată de către mediul de dezvoltare prin colorarea acesteia cu albastru.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alte comenzi utile:&lt;br /&gt;
*&amp;#039;&amp;#039;&amp;#039;Resume program&amp;#039;&amp;#039;&amp;#039; [[Fișier:CLion_resume_project.png | 16px]] - Continuă execuţia pâmă la următorul breakpoint (dacă nu există, se va executa până la final)&lt;br /&gt;
*&amp;#039;&amp;#039;&amp;#039;Stop&amp;#039;&amp;#039;&amp;#039; [[Fișier:CLion_stop.png | 16px]] - Se opreşte definitv execuţia programului, împreună cu modul debug&lt;br /&gt;
&lt;br /&gt;
[[Fișier:CLion_debug_process.png | 1000px | Imaginea 5]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pentru a exersa utilizarea sistemului de debug, realizați următoarele operații:&lt;br /&gt;
# Parcurgeti tot programul folosind &amp;#039;&amp;#039;&amp;#039;Step Over&amp;#039;&amp;#039;&amp;#039; și vizualizând valoarea variabilei &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; la fiecare pas, până la ultima linie din program, unde utilizați &amp;#039;&amp;#039;&amp;#039;Resume program&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
# Reporniți aplicația în modul de debug și puneți un al doilea &amp;#039;&amp;#039;breakpoint&amp;#039;&amp;#039; pe linia cu apelul funcției &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt;. &lt;br /&gt;
# Folosiți &amp;#039;&amp;#039;&amp;#039;Resume program&amp;#039;&amp;#039;&amp;#039; pentru a ajunge la al doilea &amp;#039;&amp;#039;breakpoint&amp;#039;&amp;#039;.&lt;br /&gt;
# Odată ajunși acolo, folosiți &amp;#039;&amp;#039;&amp;#039;Step In&amp;#039;&amp;#039;&amp;#039; pentru a intra în funcția &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; (neavând codul sursă, veți vedea codul de asamblare obținut din dezasamblarea fișierului obiect de către GDB).&lt;br /&gt;
# Folosiți &amp;#039;&amp;#039;&amp;#039;Step Out&amp;#039;&amp;#039;&amp;#039; pentru a reveni în funcția &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; și apoi &amp;#039;&amp;#039;&amp;#039;Resume program&amp;#039;&amp;#039;&amp;#039; pentru a termina execuția.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Tips &amp;amp; Tricks ==&lt;br /&gt;
&lt;br /&gt;
=== Formatare automată a codului ===&lt;br /&gt;
&lt;br /&gt;
CLion oferă opțiunea de a formata automat codul prin selectarea &amp;#039;&amp;#039;&amp;#039;Code -&amp;gt; Reformat Code&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Ce probleme rezolvă această formatare automată:&lt;br /&gt;
* alinierea liniilor în funcție de blocurile de instrucțiuni și tipurile de &amp;#039;&amp;#039;statements&amp;#039;&amp;#039; de pe fiecare linie;&lt;br /&gt;
* plasarea sau eliminarea de spații acolo unde este necasar.&lt;br /&gt;
Ce probleme NU rezolvă această formatare automată;&lt;br /&gt;
* lipsa acoladelor de la blocurile &amp;#039;&amp;#039;&amp;#039;if&amp;#039;&amp;#039;&amp;#039; și &amp;#039;&amp;#039;&amp;#039;for&amp;#039;&amp;#039;&amp;#039;;&lt;br /&gt;
* numele insuficient de sugestive pentru numele de funcții, structuri sau variabile.&lt;br /&gt;
&lt;br /&gt;
Stilul conform căruia este modificat codul poate fi configurat folosind meniul &amp;lt;code&amp;gt;File|Settings|Editor|CodeStyle&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Generare automată a codului ===&lt;br /&gt;
&lt;br /&gt;
CLion oferă posibilitatea de a genera fragmente de cod des înâlnite, precum constructori şi operatori în interiorul claselor. Această acţiune poate fi realizată folosind meniul &amp;lt;code&amp;gt; Code|Generate&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Altele ===&lt;br /&gt;
* [https://www.jetbrains.com/help/clion/using-todo.html TODO Comments]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; Nu uitați de regulile următoare: [[Convenții de cod - C]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
= Exerciții =&lt;br /&gt;
&lt;br /&gt;
*Săptămâna 1&lt;br /&gt;
*# Realizați un proiect nou în Netbeans și scrieți un program care să citească de la tastatură un număr întreg fără semn &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. Se va aloca apoi dinamic în HEAP un vector de &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; valori numerice întregi pe 16 biți. Scrieți o funcție care să citească &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; valori de la tastatură și să le plaseze în vector. Scrieți apoi o funcție care să găsească valoarea maximă din vector. Apelați în &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; funcțiile de mai sus și afișați valoarea obținută pe ecran. Nu uitați să dezalocați memoria alocată. Pentru funcțiile de alocare și dezalocare de memorie, puteți recapitula [[PC Laborator 12]].&lt;br /&gt;
*# Modificați programul de mai sus astfel încât citirea variabilei &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; cât și alocarea de memorie să fie făcută într-o funcție separată. Această funcție trebuie să întoarcă un pointer cu adresa de început a vectorului dar și dimensiunea acestuia.&lt;br /&gt;
*# Realizați un alt proiect în Netbeans și scrieți un program care să citească de la tastatură un șir de caractere de lungime maximă 255. Folosind aritmetica pointerilor și o singură buclă &amp;#039;&amp;#039;&amp;#039;for&amp;#039;&amp;#039;&amp;#039;, afișați pe ecran doar cifrele din șirul citit.&lt;br /&gt;
* Săptămâna 2&lt;br /&gt;
*# Realizați un proiect nou în Netbeans și scrieți un program care să citească de la tastatură un număr întreg fără semn &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. Scrieți apoi o funcție care să aloce memorie pentru un șir de caractere care să conțină de &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; ori secvența &amp;quot;ha&amp;quot; (spre exemplu, pentru size == 3, string-ul va trebui să conțină &amp;quot;hahaha&amp;quot;), să umple șirul cu numărul cerut de &amp;quot;ha&amp;quot;-uri și să întoarcă adresa memoriei alocate. În funcția &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; afișați șirul de caractere (nu uitați la alocare de terminatorul de sfârșit de șir). Nu uitați să dezalocați memoria. Pentru funcțiile de alocare și dezalocare de memorie, puteți recapitula [[PC Laborator 12]].&lt;br /&gt;
*# Modificați programul de mai sus astfel încât în loc de secvența &amp;quot;ha&amp;quot;, secvența repetată să fie citită de la tastatură cu &amp;lt;code&amp;gt;scanf&amp;lt;/code&amp;gt; și trimisă ca argument funcției de alocare. &lt;br /&gt;
*# Realizați un alt proiect în Netbeans și scrieți un program care să citească de la tastatură un șir de caractere de lungime maximă 255. Scrieți o singură funcție care să numere și să întoarcă numărul de litere și numărul de cifre din șirul citit. Aceste valori se vor afișa pe ecran în funcția &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Probleme propuse =&lt;br /&gt;
&lt;br /&gt;
Problemele de mai jos au anumite erori care trebuie gasite si raparate folosind debugger-ul.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problema 1 ==&lt;br /&gt;
Programul de mai jos ar trebui să citească de la tastatură un șir de maxim 1024 caractere și să afișeze câte litere mici, câte litere mari și câte cifre conține acest șir. Totuși acest program are o eroare. Folosiți debugger-ul pentru a o identifica și repara.&lt;br /&gt;
&lt;br /&gt;
Exemplu de intrare:&lt;br /&gt;
&lt;br /&gt;
Ana a plecat la piata si a cumparat 10 saci de cartofi.&lt;br /&gt;
&lt;br /&gt;
Ieșirea pentru intrarea de mai sus:&lt;br /&gt;
&lt;br /&gt;
40 1 2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C++&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    char c;&lt;br /&gt;
    unsigned uppercaseChars = 0;&lt;br /&gt;
    unsigned lowecaseChars = 0;    &lt;br /&gt;
    unsigned digits = 0;&lt;br /&gt;
    &lt;br /&gt;
    while(scanf(&amp;quot;%c&amp;quot;, c) != EOF) {&lt;br /&gt;
        if(c &amp;gt; &amp;#039;a&amp;#039; || c &amp;lt; &amp;#039;z&amp;#039;) {&lt;br /&gt;
            lowecaseChars++;&lt;br /&gt;
        } else if(c &amp;gt; &amp;#039;A&amp;#039; &amp;amp;&amp;amp; c &amp;lt; &amp;#039;Z&amp;#039;) {&lt;br /&gt;
            uppercaseChars++;&lt;br /&gt;
        } else {&lt;br /&gt;
            digits++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    printf(&amp;quot;%u %u %u&amp;quot;, lowecaseChars, uppercaseChars, digits);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problema 2 ==&lt;br /&gt;
Un tehnician a măsurat un număr mare n de rezistori şi a obţinut n valori de rezistenţe. Tehnicianul ştie că rezistorii sunt de acelaşi fel, dar pentru că sunt vechi şi codul culorilor nu mai este vizibil, doreşte să calculeze valoarea nominală a rezistenţei (R) şi dispersia valorilor, (S). Apoi, având aceste valori, el vrea să determine câte din rezistenţele testate (procentual) se încadrează în intervalul [R – S; R + S]. Rezistenţa nominală se calculează ca media aritmetică a valorilor rezistenţelor, iar formula dispersiei este dată mai jos.&lt;br /&gt;
&lt;br /&gt;
Cerinţă&lt;br /&gt;
Dându-se un număr n de rezistori şi valorile rezistenţelor acestora Ri (i = 1, ..., n), să se determine procentul rezistoarelor care au rezistenţa în intervalul [R– S; R + S].&lt;br /&gt;
&lt;br /&gt;
Date de intrare&lt;br /&gt;
Pe prima linie se află numărul întreg n. Pe următoarea linie, separate printr-un spaţiu, sunt n valori fracţionare de rezistenţe (în ohmi).&lt;br /&gt;
&lt;br /&gt;
Date de ieşire&lt;br /&gt;
Se va afişa o singură valoare fracţionară, cu exact două zecimale reprezentând procentul de rezistori cu rezistenţa în intervalul [R – S; R + S].&lt;br /&gt;
&lt;br /&gt;
Restricţii şi precizări:&lt;br /&gt;
&lt;br /&gt;
1 &amp;lt; n &amp;lt; 1000&lt;br /&gt;
&lt;br /&gt;
1.0 &amp;lt;= Ri &amp;lt;= 10000.0 &lt;br /&gt;
&lt;br /&gt;
S=sqrt( pow(sum(R[i]−R),2) / n )&lt;br /&gt;
&lt;br /&gt;
Exemplu:&lt;br /&gt;
&lt;br /&gt;
Input =&lt;br /&gt;
10&lt;br /&gt;
&lt;br /&gt;
76 1 20 37 19 92 61 96 37 77&lt;br /&gt;
&lt;br /&gt;
Output = &lt;br /&gt;
50.00&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C++&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;unordered_map&amp;gt;&lt;br /&gt;
#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    int n;&lt;br /&gt;
    double values[n];&lt;br /&gt;
    scanf(&amp;quot;%d&amp;quot;, &amp;amp;n);&lt;br /&gt;
    int sum = 0;&lt;br /&gt;
    for(int i = 0; i &amp;lt; n; i++){&lt;br /&gt;
        scanf(&amp;quot;%lf&amp;quot;, &amp;amp;values[i]);&lt;br /&gt;
        sum += values[i];&lt;br /&gt;
    }&lt;br /&gt;
    double average = sum / n;&lt;br /&gt;
    double dispersion = 0;&lt;br /&gt;
    for(int i = 0; i &amp;lt; n; i++){&lt;br /&gt;
        dispersion += (values[i] - average) * (values[i] - average);&lt;br /&gt;
    }&lt;br /&gt;
    dispersion = sqrt(dispersion / n);&lt;br /&gt;
    int larger = 0;&lt;br /&gt;
    for(int i = 0; i &amp;lt; n; i++) {&lt;br /&gt;
        if(values[i] &amp;gt;= average - dispersion &lt;br /&gt;
                &amp;amp;&amp;amp; values[i] &amp;lt;= average + dispersion) larger++;&lt;br /&gt;
    }&lt;br /&gt;
    printf(&amp;quot;%.2lf&amp;quot;, 100 * larger / n);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problema 3 ==&lt;br /&gt;
Sunteți angajați de ministerul învățamântului să scrieți un program care să listeze toți elevii care au promovat examenul de bacalaureat. De la tastatură se introduce un număr n reprezentând numărul de candidați, apoi pe următoarele n linii, un nume de elev (format din exact două cuvinte: nume și prenume) și notele la cele patru materii, format fracționar, valori între 1 și 10. Să se afișeze toți studenții care au promovat examenul de bacalaureat (media mai mare ca 6, fiecare notă mai mare ca 5) în ordinea inversă a introducerii lor, împreună cu media de promovare, afișată cu fix două zecimale.&lt;br /&gt;
&lt;br /&gt;
Exemplu de date de intrare:&lt;br /&gt;
&lt;br /&gt;
4&lt;br /&gt;
&lt;br /&gt;
Gheorghe Ghita 8 7 5.5 10&lt;br /&gt;
&lt;br /&gt;
Vuia Vasile 4 10 10 10&lt;br /&gt;
&lt;br /&gt;
Andreescu Andra 9 10 9 10&lt;br /&gt;
&lt;br /&gt;
Elenescu Elena 5 5 5 5&lt;br /&gt;
&lt;br /&gt;
Ieșirea pentru intrarea de mai sus:&lt;br /&gt;
&lt;br /&gt;
Andreescu Andra 9.50&lt;br /&gt;
&lt;br /&gt;
Gheorghe Ghita 7.63&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C++&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
struct studenti{&lt;br /&gt;
char n[128];&lt;br /&gt;
char m[128];&lt;br /&gt;
float a,b,c,d;&lt;br /&gt;
};&lt;br /&gt;
int main(){&lt;br /&gt;
int n,i;&lt;br /&gt;
struct studenti s[n];&lt;br /&gt;
scanf(&amp;quot;%d&amp;quot;, &amp;amp;n);&lt;br /&gt;
for(i=0;i&amp;lt;n;i++)&lt;br /&gt;
scanf(&amp;quot;%s%s%f%f%f%f&amp;quot;,&amp;amp;s[i].n,&amp;amp;s[i].m,&amp;amp;s[i].a,&amp;amp;s[i].b,&amp;amp;s[i].c,&amp;amp;s[i].d);&lt;br /&gt;
&lt;br /&gt;
for(i=n;i&amp;gt;0;i--){&lt;br /&gt;
float m=(s[i].a+s[i].b+s[i].c+s[i].d)/4;&lt;br /&gt;
if(s[i].a&amp;gt;5&amp;amp;&amp;amp;s[i].b&amp;gt;5&amp;amp;&amp;amp;s[i].c&amp;gt;5&amp;amp;&amp;amp;s[i].d&amp;gt;5||m&amp;gt;=6){&lt;br /&gt;
printf(&amp;quot;%s %s %.2f\n&amp;quot;,s[i].n,s[i].m,m);&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Colocviu_pclp1&amp;diff=7587</id>
		<title>Colocviu pclp1</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Colocviu_pclp1&amp;diff=7587"/>
		<updated>2024-09-07T12:01:51Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Cerință =&lt;br /&gt;
&lt;br /&gt;
­­­Sunteți la ora de matematică și tocmai ați învățat despre vectori și matrici. Pentru că întotdeauna v-au pasionat calculatoarele, ați reușit să învățați informatica de bază de timpuriu și, de asemenea, să asimilați cunoștințe despre matrici și vectori prin intermediul ei. Vi s-a dat o temă la matematică și, pentru a vă ușura munca, ați decis să scrieți un program care să rezolve cerințele din temă.&lt;br /&gt;
&lt;br /&gt;
Tema este următoarea:&lt;br /&gt;
&lt;br /&gt;
Aveți un șir de numere întregi. Pentru acest șir vi se cer următoarele:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Pentru fiecare trei numere consecutive din șir calculați media lor aritmetică și afișați mediile, separate cu câte un spațiu între ele. Pentru ușurință se va afișa un spațiu și după ultima medie. Acestea vor fi afișate ca numere fracționare, cu două zecimale după virgulă.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Pentru mediile calculate anterior, găsiți maximul dintre ele și afișați-l, tot cu 2 zecimale după virgulă.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Cu numerele pozitive (mai mari strict ca 0) și pare, vi se cere să formați un nou șir de numere și să calculați mediile aritmetice, de data aceasta pentru câte două numere. Numerele folosite pentru medii vor fi: primul cu ultimul, al doilea cu penultimul și tot așa. Dacă numărul de numere din noul șir este impar, numărul din mijloc va reprezenta el singur una dintre medii. Afișați maximul dintre aceste medii nou obținute, de asemenea cu 2 zecimale după virgulă.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Pentru șirul de numere inițiale, vi se cere să formați cea mai mare matrice pătratică care se poate realiza cu numerele din șir și să o afișați. Numerele vor fi separate pe fiecare linie cu câte un spațiu și, pentru ușurință, se va afișa un spațiu și după ultimul element de pe o linie. Toate liniile se vor termina cu un caracter newline.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; La acest subpunct vi se garantează că matricea pătratică obținută conține doar numere de o cifră. Voi trebuie să formați câte un număr pentru fiecare coloană din matrice. Numerele se formează prin alipirea respectivelor cifre, începând cu cea de pe prima linie și terminând cu cifra de pe ultima linie. Dintre numerele astfel obținute, afisați doar numerele prime, cu câte un spațiu între ele. Pentru ușurință, se va afișa un spațiu și după ultimul număr.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Datele de intrare vor fi, pentru fiecare subpunct, de forma:&lt;br /&gt;
&lt;br /&gt;
    numar_elemente&lt;br /&gt;
    elementele din sir separate cu un spatiu&lt;br /&gt;
    litera_subpunct&lt;br /&gt;
&lt;br /&gt;
unde pentru subpunctul 1, litera_subpunct este a, pentru 2: b, ș.a.m.d.&lt;br /&gt;
&lt;br /&gt;
= Exemple =&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    7 15 2 8 4 9 1 1 1 5          &lt;br /&gt;
    a&lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    8.00 8.33 4.67 7.00 4.67 3.67 1.00 2.33    &lt;br /&gt;
&lt;br /&gt;
== Explicații ==&lt;br /&gt;
&lt;br /&gt;
Media primelor trei numere este (7 + 15 + 2) / 3 = 8.00, a următoarelor trei numere: (15 + 2 + 8) / 3 = 8.33 etc.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    7 15 2 8 4 9 1 1 1 5&lt;br /&gt;
    b      &lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    8.33&lt;br /&gt;
&lt;br /&gt;
== Explicații ==&lt;br /&gt;
&lt;br /&gt;
Mediile sunt: 8.00, 8.33, 4.67, 7.00, 4.67, 3.67, 1.00, respectiv 2.33, maximul dintre ele fiind 8.33.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    16&lt;br /&gt;
    7 15 -2 8 2 -4 9 1 1 1 5 4 6 6 -8 3                             &lt;br /&gt;
    c  &lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    7.00&lt;br /&gt;
&lt;br /&gt;
== Explicații ==&lt;br /&gt;
&lt;br /&gt;
Șirul nou format din numerele pare și pozitive este: 8, 2, 4, 6, 6. Mediile vor fi: (8 + 6) / 2 = 7, (2 + 6) / 2 = 4 și 4 (doarece numărul numerelor este impar). Cea mai mare valoare dintre acestea trei este 7.00.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    7 15 2 8 4 9 1 1 1 5&lt;br /&gt;
    d &lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    7 15 2&lt;br /&gt;
    8 4 9&lt;br /&gt;
    1 1 1&lt;br /&gt;
&lt;br /&gt;
== Explicații ==&lt;br /&gt;
&lt;br /&gt;
Avem 10 numere în șir, deci cea mai mare matrice pătratică va fi formată din primele 9 numere deoarece 9 este cel mai apropiat pătrat perfect mai mic decât 10.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    1 2 3 3 5 6 7 8 7 1&lt;br /&gt;
    e&lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    137 367 &lt;br /&gt;
&lt;br /&gt;
== Explicații ==&lt;br /&gt;
&lt;br /&gt;
Matricea formată va fi:&lt;br /&gt;
&lt;br /&gt;
1 2 3&lt;br /&gt;
3 5 6&lt;br /&gt;
7 8 7&lt;br /&gt;
&lt;br /&gt;
Numerele rezultate prin alipirea cifrelor de pe fiecare coloană vor fi 137, 258 și 367, dintre care 137 și 367 sunt numere prime și ele vor fi afișate.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Colocviu_pclp1&amp;diff=7586</id>
		<title>Colocviu pclp1</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Colocviu_pclp1&amp;diff=7586"/>
		<updated>2024-09-07T12:01:25Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Cerință =&lt;br /&gt;
&lt;br /&gt;
­­­Sunteți la ora de matematică și tocmai ați învățat despre vectori și matrici. Pentru că întotdeauna v-au pasionat calculatoarele, ați reușit să învățați informatica de bază de timpuriu și, de asemenea, să asimilați cunoștințe despre matrici și vectori prin intermediul ei. Vi s-a dat o temă la matematică și, pentru a vă ușura munca, ați decis să scrieți un program care să rezolve cerințele din temă.&lt;br /&gt;
&lt;br /&gt;
Tema este următoarea:&lt;br /&gt;
&lt;br /&gt;
Aveți un șir de numere întregi. Pentru acest șir vi se cer următoarele:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Pentru fiecare trei numere consecutive din șir calculați media lor aritmetică și afișați mediile, separate cu câte un spațiu între ele. Pentru ușurință se va afișa un spațiu și după ultima medie. Acestea vor fi afișate ca numere fracționare, cu două zecimale după virgulă.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Pentru mediile calculate anterior, găsiți maximul dintre ele și afișați-l, tot cu 2 zecimale după virgulă.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Cu numerele pozitive (mai mari strict ca 0) și pare, vi se cere să formați un nou șir de numere și să calculați mediile aritmetice, de data aceasta pentru câte două numere. Numerele folosite pentru medii vor fi: primul cu ultimul, al doilea cu penultimul și tot așa. Dacă numărul de numere din noul șir este impar, numărul din mijloc va reprezenta el singur una dintre medii. Afișați maximul dintre aceste medii nou obținute, de asemenea cu 2 zecimale după virgulă.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Pentru șirul de numere inițiale, vi se cere să formați cea mai mare matrice pătratică care se poate realiza cu numerele din șir și să o afișați. Numerele vor fi separate pe fiecare linie cu câte un spațiu și, pentru ușurință, se va afișa un spațiu și după ultimul element de pe o linie. Toate liniile se vor termina cu un caracter newline.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; La acest subpunct vi se garantează că matricea pătratică obținută conține doar numere de o cifră. Voi trebuie să formați câte un număr pentru fiecare coloană din matrice. Numerele se formează prin alipirea respectivelor cifre, începând cu cea de pe prima linie și terminând cu cifra de pe ultima linie. Dintre numerele astfel obținute, afisați doar numerele prime, cu câte un spațiu între ele. Pentru ușurință, se va afișa un spațiu și după ultimul număr.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Datele de intrare vor fi, pentru fiecare subpunct, de forma:&lt;br /&gt;
&lt;br /&gt;
    numar_elemente&lt;br /&gt;
    elementele din sir separate cu un spatiu&lt;br /&gt;
    litera_subpunct&lt;br /&gt;
&lt;br /&gt;
unde pentru subpunctul 1, litera_subpunct este a, pentru 2: b, ș.a.m.d.&lt;br /&gt;
&lt;br /&gt;
= Exemple =&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    7 15 2 8 4 9 1 1 1 5          &lt;br /&gt;
    a&lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    8.00 8.33 4.67 7.00 4.67 3.67 1.00 2.33    &lt;br /&gt;
&lt;br /&gt;
== Explicații&lt;br /&gt;
&lt;br /&gt;
Media primelor trei numere este (7 + 15 + 2) / 3 = 8.00, a următoarelor trei numere: (15 + 2 + 8) / 3 = 8.33 etc.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    7 15 2 8 4 9 1 1 1 5&lt;br /&gt;
    b      &lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    8.33&lt;br /&gt;
&lt;br /&gt;
== Explicații ==&lt;br /&gt;
&lt;br /&gt;
Mediile sunt: 8.00, 8.33, 4.67, 7.00, 4.67, 3.67, 1.00, respectiv 2.33, maximul dintre ele fiind 8.33.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    16&lt;br /&gt;
    7 15 -2 8 2 -4 9 1 1 1 5 4 6 6 -8 3                             &lt;br /&gt;
    c  &lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    7.00&lt;br /&gt;
&lt;br /&gt;
== Explicații ==&lt;br /&gt;
&lt;br /&gt;
Șirul nou format din numerele pare și pozitive este: 8, 2, 4, 6, 6. Mediile vor fi: (8 + 6) / 2 = 7, (2 + 6) / 2 = 4 și 4 (doarece numărul numerelor este impar). Cea mai mare valoare dintre acestea trei este 7.00.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    7 15 2 8 4 9 1 1 1 5&lt;br /&gt;
    d &lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    7 15 2&lt;br /&gt;
    8 4 9&lt;br /&gt;
    1 1 1&lt;br /&gt;
&lt;br /&gt;
== Explicații ==&lt;br /&gt;
&lt;br /&gt;
Avem 10 numere în șir, deci cea mai mare matrice pătratică va fi formată din primele 9 numere deoarece 9 este cel mai apropiat pătrat perfect mai mic decât 10.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    1 2 3 3 5 6 7 8 7 1&lt;br /&gt;
    e&lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    137 367 &lt;br /&gt;
&lt;br /&gt;
== Explicații ==&lt;br /&gt;
&lt;br /&gt;
Matricea formată va fi:&lt;br /&gt;
&lt;br /&gt;
1 2 3&lt;br /&gt;
3 5 6&lt;br /&gt;
7 8 7&lt;br /&gt;
&lt;br /&gt;
Numerele rezultate prin alipirea cifrelor de pe fiecare coloană vor fi 137, 258 și 367, dintre care 137 și 367 sunt numere prime și ele vor fi afișate.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=Colocviu_pclp1&amp;diff=7585</id>
		<title>Colocviu pclp1</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=Colocviu_pclp1&amp;diff=7585"/>
		<updated>2024-09-07T11:58:48Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: Pagină nouă: ­­­Sunteți la ora de matematică și tocmai ați învățat despre vectori și matrici. Pentru că întotdeauna v-au pasionat calculatoarele, ați reușit să învățați info...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;­­­Sunteți la ora de matematică și tocmai ați învățat despre vectori și matrici. Pentru că întotdeauna v-au pasionat calculatoarele, ați reușit să învățați informatica de bază de timpuriu și, de asemenea, să asimilați cunoștințe despre matrici și vectori prin intermediul ei. Vi s-a dat o temă la matematică și, pentru a vă ușura munca, ați decis să scrieți un program care să rezolve cerințele din temă.&lt;br /&gt;
&lt;br /&gt;
Tema este următoarea:&lt;br /&gt;
&lt;br /&gt;
Aveți un șir de numere întregi. Pentru acest șir vi se cer următoarele:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Pentru fiecare trei numere consecutive din șir calculați media lor aritmetică și afișați mediile, separate cu câte un spațiu între ele. Pentru ușurință se va afișa un spațiu și după ultima medie. Acestea vor fi afișate ca numere fracționare, cu două zecimale după virgulă.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Pentru mediile calculate anterior, găsiți maximul dintre ele și afișați-l, tot cu 2 zecimale după virgulă.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Cu numerele pozitive (mai mari strict ca 0) și pare, vi se cere să formați un nou șir de numere și să calculați mediile aritmetice, de data aceasta pentru câte două numere. Numerele folosite pentru medii vor fi: primul cu ultimul, al doilea cu penultimul și tot așa. Dacă numărul de numere din noul șir este impar, numărul din mijloc va reprezenta el singur una dintre medii. Afișați maximul dintre aceste medii nou obținute, de asemenea cu 2 zecimale după virgulă.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; Pentru șirul de numere inițiale, vi se cere să formați cea mai mare matrice pătratică care se poate realiza cu numerele din șir și să o afișați. Numerele vor fi separate pe fiecare linie cu câte un spațiu și, pentru ușurință, se va afișa un spațiu și după ultimul element de pe o linie. Toate liniile se vor termina cu un caracter newline.&lt;br /&gt;
# &amp;#039;&amp;#039;(6p)&amp;#039;&amp;#039; La acest subpunct vi se garantează că matricea pătratică obținută conține doar numere de o cifră. Voi trebuie să formați câte un număr pentru fiecare coloană din matrice. Numerele se formează prin alipirea respectivelor cifre, începând cu cea de pe prima linie și terminând cu cifra de pe ultima linie. Dintre numerele astfel obținute, afisați doar numerele prime, cu câte un spațiu între ele. Pentru ușurință, se va afișa un spațiu și după ultimul număr.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Datele de intrare vor fi, pentru fiecare subpunct, de forma:&lt;br /&gt;
&lt;br /&gt;
    numar_elemente&lt;br /&gt;
    elementele din sir separate cu un spatiu&lt;br /&gt;
    litera_subpunct&lt;br /&gt;
&lt;br /&gt;
unde pentru subpunctul 1, litera_subpunct este a, pentru 2: b, ș.a.m.d.&lt;br /&gt;
&lt;br /&gt;
= Exemple =&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    7 15 2 8 4 9 1 1 1 5          &lt;br /&gt;
    a&lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    8.00 8.33 4.67 7.00 4.67 3.67 1.00 2.33    &lt;br /&gt;
&lt;br /&gt;
== Explicații&lt;br /&gt;
&lt;br /&gt;
Media primelor trei numere este (7 + 15 + 2) / 3 = 8.00, a următoarelor trei numere: (15 + 2 + 8) / 3 = 8.33 etc.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    7 15 2 8 4 9 1 1 1 5&lt;br /&gt;
    b      &lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    8.33&lt;br /&gt;
&lt;br /&gt;
== Explicații&lt;br /&gt;
&lt;br /&gt;
Mediile sunt: 8.00, 8.33, 4.67, 7.00, 4.67, 3.67, 1.00, respectiv 2.33, maximul dintre ele fiind 8.33.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    16&lt;br /&gt;
    7 15 -2 8 2 -4 9 1 1 1 5 4 6 6 -8 3                             &lt;br /&gt;
    c  &lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    7.00&lt;br /&gt;
&lt;br /&gt;
== Explicații&lt;br /&gt;
&lt;br /&gt;
Șirul nou format din numerele pare și pozitive este: 8, 2, 4, 6, 6. Mediile vor fi: (8 + 6) / 2 = 7, (2 + 6) / 2 = 4 și 4 (doarece numărul numerelor este impar). Cea mai mare valoare dintre acestea trei este 7.00.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    7 15 2 8 4 9 1 1 1 5&lt;br /&gt;
    d &lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    7 15 2&lt;br /&gt;
    8 4 9&lt;br /&gt;
    1 1 1&lt;br /&gt;
&lt;br /&gt;
== Explicații&lt;br /&gt;
&lt;br /&gt;
Avem 10 numere în șir, deci cea mai mare matrice pătratică va fi formată din primele 9 numere deoarece 9 este cel mai apropiat pătrat perfect mai mic decât 10.&lt;br /&gt;
&lt;br /&gt;
== Intrare ==&lt;br /&gt;
&lt;br /&gt;
    10&lt;br /&gt;
    1 2 3 3 5 6 7 8 7 1&lt;br /&gt;
    e&lt;br /&gt;
&lt;br /&gt;
== Ieșire ==&lt;br /&gt;
&lt;br /&gt;
    137 367 &lt;br /&gt;
&lt;br /&gt;
== Explicații&lt;br /&gt;
&lt;br /&gt;
Matricea formată va fi:&lt;br /&gt;
&lt;br /&gt;
1 2 3&lt;br /&gt;
3 5 6&lt;br /&gt;
7 8 7&lt;br /&gt;
&lt;br /&gt;
Numerele rezultate prin alipirea cifrelor de pe fiecare coloană vor fi 137, 258 și 367, dintre care 137 și 367 sunt numere prime și ele vor fi afișate.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=PC_Laborator_8&amp;diff=7429</id>
		<title>PC Laborator 8</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=PC_Laborator_8&amp;diff=7429"/>
		<updated>2023-01-29T09:36:27Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Căutarea unui caracter într-un șir de caractere */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Obiective == &lt;br /&gt;
  &lt;br /&gt;
în urma acestui laborator, studentul va fi capabil să: &lt;br /&gt;
*înțeleagă cum funcționează șirurile de caractere &lt;br /&gt;
*facă operații cu șiruri de caractere&lt;br /&gt;
&lt;br /&gt;
== Șiruri de caractere == &lt;br /&gt;
&lt;br /&gt;
[[Fișier:ascii_table.jpg|thumb]]&lt;br /&gt;
&lt;br /&gt;
În C, tipul de dată șir nu există în mod implicit. Singurul mod prin care putem opera cu șiruri este folosind tablourile unidimensionale, vectorii. Ne amintim că un vector este definit complet prin intermediul a trei caracteristici: tipul de date conținute, numele vectorului și numărul său de elemente. Așadar, putem declara un vector al cărui tip de data să fie char, caz în care acel vector va fi denumit șir (de caractere). &lt;br /&gt;
Declararea unui șir de caractere se face astfel: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char numele_sirului [numarul_de_caractere];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt; &amp;#039;&amp;#039;&amp;#039; Observație: &amp;#039;&amp;#039;&amp;#039; Spre deosebire de vectorii studiați în laboratorul anterior, ale căror elemente sunt precizate explicit, șirurile au un caracter special, implicit, numit end of string și reprezentat astfel: \0.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Operații cu șiruri == &lt;br /&gt;
  &lt;br /&gt;
Toate proprietățile vectorilor, studiate în laboratorul anterior, sunt valabile și în cazul șirurilor. De asemenea, toate operațiile pe care le putem face cu vectori sunt posibile și în cazul șirurilor. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt; &amp;#039;&amp;#039;&amp;#039; Observație: &amp;#039;&amp;#039;&amp;#039; Există  anumite operații asociate exclusiv șirurilor, precum căutarea unor caractere sau a unui șir într-un alt șir, concatenarea, etc. Toate aceste operații au funcții predefinite, care pot fi găsite într-un header specific, string.h. &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Aflarea lungimii unui șir de caractere === &lt;br /&gt;
Pe lângă metoda clasică, discutată în capitolul anterior, ce presupune parcurgerea șirului și numărarea elementelor acestuia, avem și o metodă proprie șirurilor. Ea presupune apelarea funcției strlen(), predefinita în biblioteca string.h, care va întoarce numărul de elemente al șirului. &lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt; &amp;#039;&amp;#039;&amp;#039; Observație: &amp;#039;&amp;#039;&amp;#039; Caracterul &amp;#039;\0&amp;#039; marchează sfârșitul șirului, iar acolo se oprește numărarea.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Sintaxa generala:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
lungime_sir = strlen (sir_de_caractere);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Citirea unui șir de caractere === &lt;br /&gt;
Există mai multe variante pentru a citi un șir de caractere, unele asemănătoare vectorilor, altele specifice șirurilor de caractere. &lt;br /&gt;
&lt;br /&gt;
1. Citirea șirului caracter cu caracter, până la întâlnirea caracterului cu codul ASCII 10 (newline - \n), moment în care se scrie caracterul de sfârșit de șir (null terminator - \0):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char sir_de_caractere[MAX_SIZE];&lt;br /&gt;
int i;&lt;br /&gt;
for (i = 0; i &amp;lt; MAX_SIZE; i++) {&lt;br /&gt;
    scanf (&amp;quot;%c&amp;quot;, &amp;amp;sir_de_caractere[i]);&lt;br /&gt;
    /* 10 este codul ascii pentru \n, adica enter */&lt;br /&gt;
    if (sir_de_caractere[i] == 10) {&lt;br /&gt;
        sir_de_caractere[i] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Se folosește &amp;lt;code&amp;gt;scanf&amp;lt;/code&amp;gt; cu template-ul &amp;lt;code&amp;gt;%s&amp;lt;/code&amp;gt; (atenție, acest &amp;lt;code&amp;gt;scanf&amp;lt;/code&amp;gt; va citi exclusiv până la primul caracter alb - spațiu, tab sau newline):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char sir_de_caractere[MAX_SIZE];&lt;br /&gt;
scanf (&amp;quot;%s&amp;quot;, sir_de_caractere);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3.  Se folosește &amp;lt;code&amp;gt;scanf&amp;lt;/code&amp;gt; cu template-ul &amp;lt;code&amp;gt;%[^\n]&amp;lt;/code&amp;gt; (atenție, acest &amp;lt;code&amp;gt;scanf&amp;lt;/code&amp;gt; va citi exclusiv până la primul newline pe care nu îl va consuma din stream - acesta va trebui eliminat manual cu apel de &amp;lt;code&amp;gt;getchar()&amp;lt;/code&amp;gt;):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char sir_de_caractere[MAX_SIZE];&lt;br /&gt;
scanf (&amp;quot;%[^\n]&amp;quot;, sir_de_caractere);&lt;br /&gt;
getchar();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Se folosește &amp;lt;code&amp;gt;fgets&amp;lt;/code&amp;gt; (atenție, acestă funcție va citi maxim MAX_SIZE - 1 caractere de la tastatură, sau până la întâlnirea lui \n, în care situație caracterul \n va fi adăugat în șir):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char sir_de_caractere[MAX_SIZE];&lt;br /&gt;
fgets(sir_de_caractere, MAX_SIZE, stdin);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Afișarea unui șir de caractere === &lt;br /&gt;
Analog citirii unui șir de caractere, afișarea se poate face și ea în mai multe moduri, după cum urmează:&lt;br /&gt;
  &lt;br /&gt;
1. Sintaxa generala:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char sir_de_caractere[MAX_SIZE]; &lt;br /&gt;
scanf(&amp;quot;%s&amp;quot;,sir_de_caractere); // citire sir de caractere&lt;br /&gt;
&lt;br /&gt;
int i;&lt;br /&gt;
for (i = 0; i &amp;lt; MAX_SIZE &amp;amp;&amp;amp; sir_de_caractere [i] != &amp;#039;\0&amp;#039;; i++) {&lt;br /&gt;
    printf (&amp;quot;%c&amp;quot;, sir_de_caractere [i]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Sintaxa generala&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
printf (&amp;quot;%s&amp;quot;, sir_de_caractere);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
3. Sintaxa generala:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
puts(sir_de_caractere);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Exemplu&amp;#039;&amp;#039;&amp;#039;: Fie șirul de caractere sir[10]. Citiți următoarea frază folosind toate cele 3 metode, apoi afișați conținutul șirului folosind puts();. Ce observați? Explicați.&lt;br /&gt;
&lt;br /&gt;
=== Căutarea unui caracter într-un șir de caractere === &lt;br /&gt;
Funcția folosită: strchr(); &lt;br /&gt;
Sintaxa generala:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char sir_de_caractere[MAX_SIZE], char caracterul_cautat;&lt;br /&gt;
char * pointer;&lt;br /&gt;
pointer = strchr(sir_de_caractere, caracterul_cautat);&lt;br /&gt;
int pozitie = pointer - sir_de_caractere;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt; &amp;#039;&amp;#039;&amp;#039; Observație: &amp;#039;&amp;#039;&amp;#039; Funcția strchr NU oferă toate pozițiile pe care se află caracterul_căutat, ci doar prima poziție. &lt;br /&gt;
*Pentru a afla ultima poziție pe care se află un caracter căutat, se va folosi funcția strrchr(), sintaxa fiind identică. &lt;br /&gt;
*Pentru a caută un șir de caractere într-un alt șir de caractere, se va folosi funcția strstr(), sintaxa fiind aceeași. &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Copierea unui șir de caractere  în altul === &lt;br /&gt;
Funcția folosită: strcpy (); &lt;br /&gt;
Sintaxa:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char destinatie[MAX_SIZE1], sursa[MAX_SIZE2];&lt;br /&gt;
strcpy(destinatie, sursa);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt; &amp;#039;&amp;#039;&amp;#039; Observație: &amp;#039;&amp;#039;&amp;#039; șirul sursă se copiază în șirul destinație. Dacă lungimea șirului destinație este mai mică decât a șirului sursă, atunci copierea se face cu erori. Trebuie deci să punem următoarea condiție: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
MAX_SIZE1 &amp;gt;= strlen(sursa);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Concatenarea unor șiruri de caractere ===&lt;br /&gt;
Funcția folosită: srtcat();&lt;br /&gt;
Sintaxa generala:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char destinatie[MAX_SIZE1], sursa[MAX_SIZE2];&lt;br /&gt;
strcat(destinatie, sursa); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt; &amp;#039;&amp;#039;&amp;#039; Observație: &amp;#039;&amp;#039;&amp;#039; Concatenarea se face adăugând șirul sursă la șirul destinație. Este deci necesar ca șirul sursă să &amp;quot;încăpă&amp;quot; în șirul destinație. Matematic, asta se traduce astfel: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
MAX_SIZE1 &amp;gt;= strlen(sursa) + strlen(destinatie); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Compararea  a doua șiruri de caractere ===&lt;br /&gt;
Funcția folosită: strcmp();&lt;br /&gt;
Sintaxa generala:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
char sir1 [MAX_SIZE1], sir2 [MAX_SIZE2];&lt;br /&gt;
int rezultat;&lt;br /&gt;
rezultat = strcmp(sir1, sir2);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Funcția strcmp(); întoarce următoarele valori: &lt;br /&gt;
* un număr negativ - dacă sir1 este înainte din punct de vedere alfabetic; &lt;br /&gt;
* 0 - dacă cele două șiruri sunt identice; &lt;br /&gt;
* un număr pozitiv - dacă sir2 este înainte din punct de vedere alfabetic.&lt;br /&gt;
&lt;br /&gt;
=== Inserția unui șir de caractere într-un alt șir === &lt;br /&gt;
Pentru această operație nu există o funcție specializată în biblioteca string.h. Ceea ce vom face va fi să folosim procedee învățate la vectori, cât și funcții menționate anterior. Etapele sunt următoarele: &lt;br /&gt;
* declarăm cele două șiruri; &lt;br /&gt;
* verificăm dacă șirul ce urmează să fie introdus încape în șirul inițial; &lt;br /&gt;
* găsim poziția unde dorim să adăugăm șirul ce urmează să fie introdus; &lt;br /&gt;
* începând cu acea poziție, mutăm toate caracterele la dreaptă cu un număr de poziții egal cu lungimea șirului ce urmează să fie introdus; &lt;br /&gt;
* pe pozițiile rămase &amp;quot;goale&amp;quot; introducem șirul nou. &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Exemplu:&amp;#039;&amp;#039;&amp;#039;  &lt;br /&gt;
Transformați fraza &amp;quot;Studentul a picat examenul final.&amp;quot; în &amp;quot;Studentul nu a picat examenul final.&amp;quot; &lt;br /&gt;
Date necesare: sir_inițial[50] = &amp;quot;Sudentul a picat examenul final.&amp;quot;, sir_nou[3] = &amp;quot;nu &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Observații și exemple==&lt;br /&gt;
&lt;br /&gt;
=== strlen vs sizeof ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
	char str1[20] = &amp;quot;StringLab&amp;quot;;&lt;br /&gt;
	int len,size;&lt;br /&gt;
&lt;br /&gt;
	len = strlen(str1);&lt;br /&gt;
	size = sizeof(str1); &lt;br /&gt;
	printf(&amp;quot;Lungimea str1: %d\n&amp;quot;, len);&lt;br /&gt;
	printf(&amp;quot;Lungimea total alocata str1: %d\n&amp;quot;, size);&lt;br /&gt;
&lt;br /&gt;
     return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== strchr vs strrchr ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
    	char str1[40] = &amp;quot;Cautare de caracter printre caractere&amp;quot;;&lt;br /&gt;
    	printf (&amp;quot;Caz1: %s\n&amp;quot;, strchr(str1, &amp;#039;a&amp;#039;));&lt;br /&gt;
    	printf (&amp;quot;Caz2: %s\n&amp;quot;, strrchr(str1, &amp;#039;a&amp;#039;));&lt;br /&gt;
        printf (&amp;quot;Caz3: %s\n&amp;quot;, strstr(str1, &amp;quot;de&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
     return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple operații cu șiruri===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main () {&lt;br /&gt;
&lt;br /&gt;
   char str1[10] = &amp;quot;Hello&amp;quot;;&lt;br /&gt;
   char str2[10] = &amp;quot;String Lab&amp;quot;;&lt;br /&gt;
   char str3[10];&lt;br /&gt;
   int  len ;&lt;br /&gt;
&lt;br /&gt;
   /* copiaza str1 in str3 */&lt;br /&gt;
   strcpy(str3, str1);&lt;br /&gt;
   printf(&amp;quot;strcpy( str3, str1) :  %s\n&amp;quot;, str3 );&lt;br /&gt;
&lt;br /&gt;
   /* concateneaza str1 str2 */&lt;br /&gt;
   strcat( str1, str2);&lt;br /&gt;
   printf(&amp;quot;strcat( str1, str2):   %s\n&amp;quot;, str1 );&lt;br /&gt;
&lt;br /&gt;
   /* lungimea str1 dupa concatenare */&lt;br /&gt;
   len = strlen(str1);&lt;br /&gt;
   printf(&amp;quot;strlen(str1) :  %d\n&amp;quot;, len );&lt;br /&gt;
&lt;br /&gt;
   return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Model de concatenare fără a utiliza strcat ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(){&lt;br /&gt;
&lt;br /&gt;
   char str1[10], str2[10], str3[20];&lt;br /&gt;
   int i, poz;&lt;br /&gt;
   printf(&amp;quot;Introduceti sir1: &amp;quot;);&lt;br /&gt;
   scanf(&amp;quot;%s&amp;quot;,str1);&lt;br /&gt;
   printf(&amp;quot;Introduceti sir2: &amp;quot;);&lt;br /&gt;
   scanf(&amp;quot;%s&amp;quot;,str2);&lt;br /&gt;
&lt;br /&gt;
	for (i = 0; i &amp;lt; strlen(str1); i++)&lt;br /&gt;
		str3[i] = str1[i];&lt;br /&gt;
		poz=i;&lt;br /&gt;
	for (i = 0; i &amp;lt; strlen(str2); i++)&lt;br /&gt;
		str3[poz+i] = str2[i];&lt;br /&gt;
		str3[poz+i] =&amp;#039;\0&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
   printf(&amp;quot;Sir concatenat: %s\n&amp;quot;,str3); &lt;br /&gt;
&lt;br /&gt;
return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple fgets &amp;amp; puts ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
int main(){&lt;br /&gt;
    char nume[30];&lt;br /&gt;
    printf(&amp;quot;Numele este: &amp;quot;);&lt;br /&gt;
   /* Citește string de la utilizator */&lt;br /&gt;
    fgets(nume, 30, stdin);     &lt;br /&gt;
    printf(&amp;quot;Nume: &amp;quot;);&lt;br /&gt;
   /* Afișează string */&lt;br /&gt;
    puts(nume);    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exerciții ==&lt;br /&gt;
&lt;br /&gt;
#Să se scrie un program care citește de la tastatură un cuvânt.Să se afișeze cuvintele ce se obțin prin eliminarea succesiva a primei si ultimei litere din cuvântul citit.&lt;br /&gt;
#Să se scrie un program care șterge toate caracterele dintr-o linie citită de la tastatură cu excepția literelor.&lt;br /&gt;
#Să se scrie un program care afișează pe ecran frecvența de apariție a unui caracter citit de la tastatură.&lt;br /&gt;
#Se citeşte de la tastatură o propoziţie (şir de caractere) terminată cu punct.Să se afişeze fiecare cuvânt din propoziţie pe câte o linie separată.&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=CID_aplicatii_9_:_Numaratorul&amp;diff=7388</id>
		<title>CID aplicatii 9 : Numaratorul</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=CID_aplicatii_9_:_Numaratorul&amp;diff=7388"/>
		<updated>2022-04-20T17:05:32Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Exemplul 1: Implementarea unui num[r[tor cu reset sincron */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Numărătorul ==&lt;br /&gt;
Numărătorul este cel mai simplu automat, fiind format dintr-un registru (element de memorare) ce reține valoarea curentă a acestuia și un circuit de incrementare (circuit de reacție) ce generează la ieșirea sa valoarea ce va trebui stocată în registru la următorul front crescător de ceas (valoarea curentă incrementată cu 1). &lt;br /&gt;
&lt;br /&gt;
În figura de mai jos este reprezentat un numărător cu reset sincron:&lt;br /&gt;
&lt;br /&gt;
[[Fișier:Numarator cu reset.png|600px]]&lt;br /&gt;
&lt;br /&gt;
În cazul de mai sus, cât timp semnalul &amp;#039;&amp;#039;reset&amp;#039;&amp;#039; este activ, valoarea numărătorului va fi 0. Atunci când semnalul &amp;#039;&amp;#039;reset&amp;#039;&amp;#039; nu este activ, numărătorul își va incrementa valoarea la fiecare front crescător de ceas.&lt;br /&gt;
&lt;br /&gt;
== Divizor de frecvență cu factor de divizare putere a lui 2==&lt;br /&gt;
În unele cazuri, apare necesitatea obținerii unor semnale de ceas cu frecvență mai mică decât cea a ceasului de sistem. Aceste noi semnale de ceas pot fi obținute chiar din semnalul de ceas al sistemului, prin circuite care realizează divizarea acestuia. Cea mai simplă divizare a unui semnal de ceas este cea cu factor de divizare egal cu o putere a lui 2. Pentru acest caz, putem folosi un numărător.&lt;br /&gt;
&lt;br /&gt;
Dacă urmărim figura de mai jos în care sunt reprezentate variațiile fiecărui bit în timpul funcționării unui numărător pe 4 biți, observăm că, cu cât ordinul bitului crește (este mai semnificativ), frecvența de variație este mai mică. Între frecvențele de variație corespunzătoare a doi biți succesivi există următoarea relație: frecvența unui bit este de două ori mai mică decât frecvența bitului anterior (mai puțin semnificativ).&lt;br /&gt;
&lt;br /&gt;
[[Fișier:Divizare frecventa.png]]&lt;br /&gt;
&lt;br /&gt;
Observând că frecvența bitului 0 este de două ori mai mică decât cea a ceasului, putem concluziona că frecvența de variație a bitului cu indicele N este dată de: &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;f&amp;lt;sub&amp;gt;bN&amp;lt;/sub&amp;gt;&amp;#039;&amp;#039; = &amp;#039;&amp;#039;f&amp;lt;sub&amp;gt;clk&amp;lt;/sub&amp;gt; / 2&amp;lt;sup&amp;gt;N+1&amp;lt;/sup&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Așadar, pentru a realiza un divizor de frecvență cu factor de divizare putere a lui 2, putem folosi un numărător îndeajuns de mare, din care extragem bitul cu frecvența de variație egală cu frecvența dorită.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Exemple==&lt;br /&gt;
===Exemplul 1: Implementarea unui numărător cu reset sincron===&lt;br /&gt;
În acest exemplu vom realiza implementarea numărătorului cu reset sincron prezentat în figura din secțiunea de introducere teoretică. În plus, vom folosi parametrul WIDTH pentru a controla dimensiunea acestuia.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Implementarea Numărătorului cu reset sincron&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Verilog&amp;quot;&amp;gt;&lt;br /&gt;
module Numarator&lt;br /&gt;
#(parameter WIDTH = 8)&lt;br /&gt;
(&lt;br /&gt;
    input clock,&lt;br /&gt;
    input reset,&lt;br /&gt;
    output reg [WIDTH-1:0] count  &lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
always@(posedge clock) begin&lt;br /&gt;
    if(reset == 0)&lt;br /&gt;
        count &amp;lt;= 0;&lt;br /&gt;
    else&lt;br /&gt;
        count &amp;lt;= count + 1;  &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Implementarea unui modul de test pentru numărător&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Verilog&amp;quot;&amp;gt;&lt;br /&gt;
`timescale 1ns/1ps&lt;br /&gt;
&lt;br /&gt;
module Numarator_TB();&lt;br /&gt;
&lt;br /&gt;
parameter WIDTH_T = 5;&lt;br /&gt;
reg reset_t, clock_t;&lt;br /&gt;
wire [WIDTH_T-1:0] count_t;&lt;br /&gt;
	&lt;br /&gt;
initial begin&lt;br /&gt;
    clock_t = 0;&lt;br /&gt;
    forever #1 clock_t = ~clock_t;&lt;br /&gt;
end&lt;br /&gt;
	&lt;br /&gt;
initial begin&lt;br /&gt;
        reset_t = 0;&lt;br /&gt;
    #2 	reset_t = 1;&lt;br /&gt;
    #500 $stop();	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
Numarator #(.WIDTH(WIDTH_T)) DUT(&lt;br /&gt;
    .clock(clock_t),&lt;br /&gt;
    .reset(reset_t),&lt;br /&gt;
    .count(count_t)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Observație:&amp;#039;&amp;#039;&amp;#039; Cât timp semnalul &amp;#039;&amp;#039;reset&amp;#039;&amp;#039; este inactiv, numărătorul își va incrementa valoarea la fiecare front crescător de ceas. Când va ajunge la valoarea sa maximă (de exemplu, 31 pentru un numărător pe 5 biți), va avea loc o depășire și având la dispozitie un număr limitat de biți (de exemplu, 5), semnalul de ieșire va deveni 0 (reținem doar cei mai puțin semnificativi 5 biți), circuitul reluând numărarea de la capat.&lt;br /&gt;
&lt;br /&gt;
===Exemplul 2: Observarea vitezei de variație a biților unui numărător===&lt;br /&gt;
În acest exemplu vom realiza implementarea unui divizor de frecvență ce generează la ieșire 4 semnale de ceas cu următoarele frecvențe:&lt;br /&gt;
* &amp;#039;&amp;#039;clkout1&amp;#039;&amp;#039;: semnal de ceas cu frecvența de 1 Hz.&lt;br /&gt;
* &amp;#039;&amp;#039;clkout2&amp;#039;&amp;#039;: semnal de ceas cu frecvența de 2 Hz.&lt;br /&gt;
* &amp;#039;&amp;#039;clkout4&amp;#039;&amp;#039;: semnal de ceas cu frecvența de 4 Hz.&lt;br /&gt;
* &amp;#039;&amp;#039;clkout8&amp;#039;&amp;#039;: semnal de ceas cu frecvența de 8 Hz.&lt;br /&gt;
&lt;br /&gt;
Dacă aplicăm formula &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;f&amp;lt;sub&amp;gt;bN&amp;lt;/sub&amp;gt;&amp;#039;&amp;#039; = &amp;#039;&amp;#039;f&amp;lt;sub&amp;gt;clk&amp;lt;/sub&amp;gt; / 2&amp;lt;sup&amp;gt;N+1&amp;lt;/sup&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; cunoscând că frecvența de ceas a FPGA-ului este de 125 MHz, vom obține:&lt;br /&gt;
* &amp;#039;&amp;#039;clkout1&amp;#039;&amp;#039; poate fi obținut prin bitul 26 al unui numărător.&lt;br /&gt;
* &amp;#039;&amp;#039;clkout2&amp;#039;&amp;#039; poate fi obținut prin bitul 25 al unui numărător.&lt;br /&gt;
* &amp;#039;&amp;#039;clkout4&amp;#039;&amp;#039; poate fi obținut prin bitul 24 al unui numărător.&lt;br /&gt;
* &amp;#039;&amp;#039;clkout8&amp;#039;&amp;#039; poate fi obținut prin bitul 23 al unui numărător.&lt;br /&gt;
&lt;br /&gt;
Din rezultatele de mai sus, rezultă că avem nevoie de un numărător pe 27 biți, astfel încât să putem folosi bitul cel mai semnificativ (bitul 26) pentru generarea semnalului de ceas cu frecvența cea mai mică.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Implementarea Verilog a circuitului&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Verilog&amp;quot;&amp;gt;&lt;br /&gt;
module clock_generator(&lt;br /&gt;
    input clock,&lt;br /&gt;
    input reset,&lt;br /&gt;
    output clkout1,&lt;br /&gt;
    output clkout2,&lt;br /&gt;
    output clkout4,&lt;br /&gt;
    output clkout8,&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
reg [26:0] count;&lt;br /&gt;
&lt;br /&gt;
always@(posedge clock) begin&lt;br /&gt;
    if(reset == 0)&lt;br /&gt;
        count &amp;lt;= 0;&lt;br /&gt;
    else&lt;br /&gt;
        count &amp;lt;= count + 1;  &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
assign clkout1 = count[26];&lt;br /&gt;
assign clkout2 = count[25];&lt;br /&gt;
assign clkout4 = count[24];&lt;br /&gt;
assign clkout8 = count[23];&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Implementarea circuitului pe FPGA&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Realizați sinteza circuitului pe FPGA, ținând cont de următoarele constrângeri de I/O:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-  align=&amp;quot;center&amp;quot;&lt;br /&gt;
||&amp;#039;&amp;#039;&amp;#039;Port&amp;#039;&amp;#039;&amp;#039; || &amp;#039;&amp;#039;&amp;#039;Conexiune&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
|-  align=&amp;quot;center&amp;quot;&lt;br /&gt;
| clock || CLK_125MHz&lt;br /&gt;
|-  align=&amp;quot;center&amp;quot;&lt;br /&gt;
| reset || Button 0 &lt;br /&gt;
|-  align=&amp;quot;center&amp;quot;&lt;br /&gt;
| clkout1 || LED3&lt;br /&gt;
|-  align=&amp;quot;center&amp;quot;&lt;br /&gt;
| clkout2  || LED2&lt;br /&gt;
|-  align=&amp;quot;center&amp;quot;&lt;br /&gt;
| clkout4  || LED1 &lt;br /&gt;
|-  align=&amp;quot;center&amp;quot;&lt;br /&gt;
| clkout8  || LED0 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Observați viteza cu care fiecare din LED-uri se stinge și se aprinde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Exerciții==&lt;br /&gt;
===Exercițiul 1===&lt;br /&gt;
Implementați un numărător parametrizat cu reset sincron și semnal de &amp;#039;&amp;#039;enable&amp;#039;&amp;#039;. Semnalul &amp;#039;&amp;#039;enable&amp;#039;&amp;#039; controlează funcționarea numărătorului astfel: când este activ (egal cu 1), permite funcționarea normală (incrementare la fiecare front crescător de ceas); când este inactiv (egal cu 0), va determina numărătorul să își păstreze valoarea curentă.&lt;br /&gt;
&lt;br /&gt;
Implementați și un modul de test care să testeze funcționarea corectă a circuitului.&lt;br /&gt;
&lt;br /&gt;
===Exercițiul 2===&lt;br /&gt;
Implementați un numărător parametrizat cu reset sincron și capacitatea de a număra crescător sau descrescător. Controlul direcției de numărare se va realiza cu ajutorul unui semnal &amp;#039;&amp;#039;count_updown&amp;#039;&amp;#039;, care controlează funcționarea numărătorului astfel: când este 0, numărătorul va număra crescător, prin incrementarea valorii curente, iar când este 1, numărătorul va număra descrescător, prin decrementarea valorii curente&lt;br /&gt;
&lt;br /&gt;
Implementați și un modul de test care să testeze funcționarea corectă a circuitului.&lt;br /&gt;
&lt;br /&gt;
===Exercițiul 3===&lt;br /&gt;
Implementați circuitul descris prin schema de mai jos, știind că:&lt;br /&gt;
* COUNTER este un numărător pe 32 biți fără reset.&lt;br /&gt;
* RAM este o memorie 16x4b, cu citire sincrona.&lt;br /&gt;
* ROM este o memorie 16x4b, ce are descrierea prezentată mai jos.&lt;br /&gt;
&lt;br /&gt;
[[Fișier:Cid_lab6.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Implementarea modulului ROM&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Verilog&amp;quot;&amp;gt;&lt;br /&gt;
module ROM(&lt;br /&gt;
    input [3:0] in,&lt;br /&gt;
    output reg [3:0] out&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
always @(in)&lt;br /&gt;
    case(in)&lt;br /&gt;
        0: out = 4&amp;#039;b0000;&lt;br /&gt;
        1: out = 4&amp;#039;b0110;&lt;br /&gt;
        2: out = 4&amp;#039;b0011;&lt;br /&gt;
        3: out = 4&amp;#039;b1110;&lt;br /&gt;
        4: out = 4&amp;#039;b1011;&lt;br /&gt;
        5: out = 4&amp;#039;b1111;&lt;br /&gt;
        6: out = 4&amp;#039;b0111;&lt;br /&gt;
        7: out = 4&amp;#039;b1100;&lt;br /&gt;
        8: out = 4&amp;#039;b0001;&lt;br /&gt;
        9: out = 4&amp;#039;b0101;&lt;br /&gt;
        10: out = 4&amp;#039;b1101;&lt;br /&gt;
        11: out = 4&amp;#039;b1010;&lt;br /&gt;
        12: out = 4&amp;#039;b0010;&lt;br /&gt;
        13: out = 4&amp;#039;b0100;&lt;br /&gt;
        14: out = 4&amp;#039;b1000;&lt;br /&gt;
        15: out = 4&amp;#039;b1001;&lt;br /&gt;
        default: out = 4&amp;#039;b0000;&lt;br /&gt;
    endcase&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Realizați un modul de test în care să scrieți memoria RAM cu date, astfel încât să se realizeze citirea memoriei ROM în ordine, la fiecare ciclu de ceas (adresa 0 -&amp;gt; adresa 1 -&amp;gt; ... -&amp;gt; adresa 15 -&amp;gt; adresa 0 -&amp;gt; ...)&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
	<entry>
		<id>http://wiki.dcae.pub.ro/index.php?title=C%2B%2B_POO_Lab_Lucrarea_4&amp;diff=7370</id>
		<title>C++ POO Lab Lucrarea 4</title>
		<link rel="alternate" type="text/html" href="http://wiki.dcae.pub.ro/index.php?title=C%2B%2B_POO_Lab_Lucrarea_4&amp;diff=7370"/>
		<updated>2022-04-12T22:01:59Z</updated>

		<summary type="html">&lt;p&gt;Rhobincu: /* Exemplu */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Această lucrare are ca scop familiarizarea cu următoarele noțiuni:&lt;br /&gt;
&lt;br /&gt;
* Moștenirea&lt;br /&gt;
* Ascunderea metodelor&lt;br /&gt;
* Polimorfismul&lt;br /&gt;
* Metode virtuale și suprascrierea metodelor&lt;br /&gt;
* Metode pur virtuale și clase abstracte&lt;br /&gt;
&lt;br /&gt;
= Moștenirea =&lt;br /&gt;
&lt;br /&gt;
== Introducere ==&lt;br /&gt;
Moștenirea este mecanismul prin care o clasă preia structura (câmpurile) și comportamentul (metodele) unei alte (sau mai multor) clase, la care poate adăuga alți membri specifici.&lt;br /&gt;
&lt;br /&gt;
Clasa de la care se preiau membrii se numește:&lt;br /&gt;
* clasă de bază&lt;br /&gt;
* superclasă&lt;br /&gt;
&lt;br /&gt;
Clasa nouă, care preia membrii de la clasa de bază se numește:&lt;br /&gt;
* clasă derivată&lt;br /&gt;
* clasă extinsă&lt;br /&gt;
* subclasă&lt;br /&gt;
&lt;br /&gt;
În C++, moștenirea poate fi multiplă, în sensul că o clasă derivată poate moșteni mai multe clase de bază. Nu în toate limbajele există acest concept (în Java, de exemplu, există doar moștenire simplă - adică o clasă poate moșteni o singură altă clasă).&lt;br /&gt;
&lt;br /&gt;
Utilitatea moștenirii în programarea orientată pe obiecte este:&lt;br /&gt;
* reutilizarea codului existent fără modificarea acestuia;&lt;br /&gt;
* extinderea a unei clase deja scrise, fără a fi necesară recompilarea ei;&lt;br /&gt;
* utilizarea polimorfismului în timpul execuției, prin folosirea metodelor virtuale.&lt;br /&gt;
&lt;br /&gt;
== Exemplu ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C++&amp;quot; line highlight=&amp;quot;29&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class Animal {&lt;br /&gt;
    std::string mName;&lt;br /&gt;
    std::string mColor;&lt;br /&gt;
    int mAge;&lt;br /&gt;
protected:&lt;br /&gt;
    bool mHasFeathers;&lt;br /&gt;
&lt;br /&gt;
public:&lt;br /&gt;
    void makeSound() const {&lt;br /&gt;
        printf(&amp;quot;Animal %s makes a sound!\n&amp;quot;, mName.c_str());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a getter method&lt;br /&gt;
    std::string getName() const {&lt;br /&gt;
        return mName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a setter method&lt;br /&gt;
    void setAge(int age) {&lt;br /&gt;
        if(age &amp;gt; 0) {&lt;br /&gt;
            mAge = age;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class Cat : public Animal {&lt;br /&gt;
    unsigned int mLives;&lt;br /&gt;
public:&lt;br /&gt;
    Cat() : mLives(9) {&lt;br /&gt;
        mHasFeathers = false;&lt;br /&gt;
    }&lt;br /&gt;
}; &lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    Cat cat;&lt;br /&gt;
    cat.makeSound(); // makeSound este mostenita din clasa Animal&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
În exemplul de mai sus, clasa &amp;lt;code&amp;gt;Cat&amp;lt;/code&amp;gt; preia toți membrii din clasa &amp;lt;code&amp;gt;Animal&amp;lt;/code&amp;gt; și adaugă un câmp &amp;lt;code&amp;gt;mLives&amp;lt;/code&amp;gt; și un constructor fără argumente. S-a introdus, de asemenea, un nou modificator de acces, &amp;lt;code&amp;gt;protected&amp;lt;/code&amp;gt;, care permite accesul la membrul respectiv atât din clasa curentă cât și din orice clasă derivată din clasa curentă, dar nu și din alte clase sau funcții.&lt;br /&gt;
&lt;br /&gt;
Se observă, de asemenea, că moștenirea a fost declarată publică. Există două timpuri de moșteniri:&lt;br /&gt;
# publică&lt;br /&gt;
# privată&lt;br /&gt;
&lt;br /&gt;
Relativ la tipul de moștenire, mai jos este prezentat modul în care se preiau membrii din clasa de bază:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Accesul asupra membrilor moșteniți&lt;br /&gt;
|-&lt;br /&gt;
! Protecția in clasa de baza !! Modificatorul de acces utilizat în lista claselor de bază !! Dreptul de acces în clasa derivată&lt;br /&gt;
|-&lt;br /&gt;
| public || public || public&lt;br /&gt;
|-&lt;br /&gt;
| private || public || inaccesibil&lt;br /&gt;
|-&lt;br /&gt;
| protected || public || protected&lt;br /&gt;
|-&lt;br /&gt;
| public || private || private&lt;br /&gt;
|-&lt;br /&gt;
| private || private || inaccesibil&lt;br /&gt;
|-&lt;br /&gt;
| protected || private || private&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt;&amp;lt;font color=&amp;quot;#ff0000&amp;quot;&amp;gt;Atenție: &amp;lt;/font&amp;gt;A doua diferență între &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; și &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; este că pentru prima, moștenirea implicită este &amp;#039;&amp;#039;&amp;#039;private&amp;#039;&amp;#039;&amp;#039; iar pentru a doua este &amp;#039;&amp;#039;&amp;#039;public&amp;#039;&amp;#039;&amp;#039;.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Apelul constructorului superclasei ==&lt;br /&gt;
&lt;br /&gt;
Când se instanțiază o clasă derivată, constructorul acestei clase se ocupă de inițializarea câmpurilor definite în clasa derivată. Pentru a inițializa câmpurile din clasa de bază, este necesar să apelăm constructorul ei. Prin urmare:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt;&amp;lt;font color=&amp;quot;#ff0000&amp;quot;&amp;gt;Atenție: &amp;lt;/font&amp;gt;Obligatoriu, constructorul unei clase derivate trebuie să apeleze constructorul clasei de bază. Dacă acest apel nu se face explicit, compilatorul va introduce un apel către constructorul clasei de bază fără argumente. Dacă acesta lipsește, apelul către constructorul clasei de bază trebuie făcut explicit, altfel se va genera o eroare de compilare.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apelul constructorului superclasei se face folosind aceeași sintaxă ca pentru inițializarea câmpurilor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C++&amp;quot; line highlight=&amp;quot;32&amp;quot;&amp;gt;&lt;br /&gt;
class Animal {&lt;br /&gt;
    std::string mName;&lt;br /&gt;
    std::string mColor;&lt;br /&gt;
    int mAge;&lt;br /&gt;
protected:&lt;br /&gt;
    bool mHasFeathers;&lt;br /&gt;
&lt;br /&gt;
public:&lt;br /&gt;
    Animal(const std::string &amp;amp; name, const std::string &amp;amp; color) : mName(name), mColor(color) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void makeSound() const {&lt;br /&gt;
        printf(&amp;quot;Animal %s makes a sound!\n&amp;quot;, mName.c_str());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a getter method&lt;br /&gt;
    std::string getName() const {&lt;br /&gt;
        return mName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a setter method&lt;br /&gt;
    void setAge(int age) {&lt;br /&gt;
        if(age &amp;gt; 0) {&lt;br /&gt;
            mAge = age;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class Cat : public Animal {&lt;br /&gt;
    unsigned int mLives;&lt;br /&gt;
public:&lt;br /&gt;
    Cat(const std::string &amp;amp; name, const std::string &amp;amp; color) : Animal(name, color), mLives(9) {&lt;br /&gt;
        mHasFeathers = false;&lt;br /&gt;
    }&lt;br /&gt;
}; &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Ascunderea metodelor =&lt;br /&gt;
&lt;br /&gt;
În anumite situații, există nevoia ca o anumită metodă care este moștenită din clasa de bază să se comporte altfel în clasa derivată. Putem realiza acest lucru reimplementând metoda respectivă, cu aceeași semnătură, în clasa derivată. Acest mecanism se numește ascundere (hiding):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C++&amp;quot; line highlight=&amp;quot;39-41&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class Animal {&lt;br /&gt;
    std::string mName;&lt;br /&gt;
    std::string mColor;&lt;br /&gt;
    int mAge;&lt;br /&gt;
protected:&lt;br /&gt;
    bool mHasFeathers;&lt;br /&gt;
&lt;br /&gt;
public:&lt;br /&gt;
    Animal(const std::string &amp;amp; name, const std::string &amp;amp; color) : mName(name), mColor(color) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void makeSound() const {&lt;br /&gt;
        printf(&amp;quot;Animal %s makes a sound!\n&amp;quot;, mName.c_str());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a getter method&lt;br /&gt;
    std::string getName() const {&lt;br /&gt;
        return mName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a setter method&lt;br /&gt;
    void setAge(int age) {&lt;br /&gt;
        if(age &amp;gt; 0) {&lt;br /&gt;
            mAge = age;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class Cat : public Animal {&lt;br /&gt;
    unsigned int mLives;&lt;br /&gt;
public:&lt;br /&gt;
    Cat(const std::string &amp;amp; name, const std::string &amp;amp; color) : Animal(name, color), mLives(9) {&lt;br /&gt;
        mHasFeathers = false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void makeSound() const {&lt;br /&gt;
        printf(&amp;quot;Cat %s meows!\n&amp;quot;, getName().c_str());&lt;br /&gt;
    }&lt;br /&gt;
}; &lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    Animal animal(&amp;quot;Rex&amp;quot;, &amp;quot;black&amp;quot;);&lt;br /&gt;
    animal.makeSound();&lt;br /&gt;
    Cat cat(&amp;quot;Spot&amp;quot;, &amp;quot;tabby&amp;quot;);&lt;br /&gt;
    cat.makeSound();&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ieșire:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Animal Rex makes a sound!&lt;br /&gt;
Cat Spot meows!&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Polimorfismul =&lt;br /&gt;
&lt;br /&gt;
== Introducere ==&lt;br /&gt;
Polimorfismul -- din greacă &amp;quot;poly&amp;quot; (mai multe) and &amp;quot;morphe&amp;quot; (forme) -- se referă la faptul că un obiect care este de tipul unei clase derivate, este în același timp și de tipul clasei de bază. Altfel spus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt;&amp;lt;font color=&amp;quot;#ff0000&amp;quot;&amp;gt;Atenție: &amp;lt;/font&amp;gt;Dacă o clasă &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; extinde (direct sau indirect) o clasă &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, atunci un obiect &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; de tipul &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; este în același timp și de tipul &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Folosind acest concept, care este implementat și în limbajul C++, se pot utiliza pointeri sau referințe de un tip &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; pentru a referi obiecte de tipuri derivate din &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Exemplu ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C++&amp;quot; line highlight=&amp;quot;50&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class Animal {&lt;br /&gt;
    std::string mName;&lt;br /&gt;
    std::string mColor;&lt;br /&gt;
    int mAge;&lt;br /&gt;
protected:&lt;br /&gt;
    bool mHasFeathers;&lt;br /&gt;
&lt;br /&gt;
public:&lt;br /&gt;
    Animal(const std::string &amp;amp; name, const std::string &amp;amp; color) : mName(name), mColor(color) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void makeSound() const {&lt;br /&gt;
        printf(&amp;quot;Animal %s makes a sound!\n&amp;quot;, mName.c_str());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a getter method&lt;br /&gt;
    std::string getName() const {&lt;br /&gt;
        return mName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a setter method&lt;br /&gt;
    void setAge(int age) {&lt;br /&gt;
        if(age &amp;gt; 0) {&lt;br /&gt;
            mAge = age;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class Cat : public Animal {&lt;br /&gt;
    unsigned int mLives;&lt;br /&gt;
public:&lt;br /&gt;
    Cat(const std::string &amp;amp; name, const std::string &amp;amp; color) : Animal(name, color), mLives(9) {&lt;br /&gt;
        mHasFeathers = false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void makeSound() const {&lt;br /&gt;
        printf(&amp;quot;Cat %s meows!\n&amp;quot;, getName().c_str());&lt;br /&gt;
    }&lt;br /&gt;
}; &lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    Animal animal(&amp;quot;Rex&amp;quot;, &amp;quot;black&amp;quot;);&lt;br /&gt;
    Cat cat(&amp;quot;Spot&amp;quot;, &amp;quot;tabby&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    Animal &amp;amp; animalRef = animal;&lt;br /&gt;
    Cat &amp;amp; catRef = cat;&lt;br /&gt;
    Animal &amp;amp; catRef2 = cat;&lt;br /&gt;
&lt;br /&gt;
    animalRef.makeSound();&lt;br /&gt;
    catRef.makeSound();&lt;br /&gt;
    catRef2.makeSound();&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ieșire:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Animal Rex makes a sound!&lt;br /&gt;
Cat Spot meows!&lt;br /&gt;
Animal Spot makes a sound!&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se vede că pe linia 50 de mai sus, avem o referință de tip &amp;lt;code&amp;gt;Animal&amp;lt;/code&amp;gt; la un obiect de tip &amp;lt;code&amp;gt;Cat&amp;lt;/code&amp;gt;. Acest lucru este posibil pentru că o &amp;lt;code&amp;gt;Cat&amp;lt;/code&amp;gt; este în același timp și un &amp;lt;code&amp;gt;Animal&amp;lt;/code&amp;gt; (deoarece &amp;lt;code&amp;gt;Cat&amp;lt;/code&amp;gt; extinde &amp;lt;code&amp;gt;Animal&amp;lt;/code&amp;gt;). Totuși, se poate observa din textul de ieșire că deși referințele &amp;lt;code&amp;gt;catRef&amp;lt;/code&amp;gt; și &amp;lt;code&amp;gt;catRef2&amp;lt;/code&amp;gt; sunt către același obiect (de tip &amp;lt;code&amp;gt;Cat&amp;lt;/code&amp;gt;), apelul metodei &amp;lt;code&amp;gt;makeSound&amp;lt;/code&amp;gt; se face în funcție de tipul referinței, nu de tipul obiectului. Există însă scenarii în care se dorește comportamentul invers, anume apelul metodei în funcție de tipul obiectului, nu de tipul referinței cu care este accesat. Astfel, se introduce conceptul de &amp;#039;&amp;#039;&amp;#039;metodă virtuală&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
= Metode virtuale și suprascrierea metodelor =&lt;br /&gt;
== Introducere ==&lt;br /&gt;
&lt;br /&gt;
Dacă o metodă este declarată virtuală, folosind cuvântul cheie &amp;lt;code&amp;gt;virtual&amp;lt;/code&amp;gt; plasat în fața tipului întors, atunci reimplementarea acesteia în clasele derivate se numește &amp;#039;&amp;#039;&amp;#039;suprascriere&amp;#039;&amp;#039;&amp;#039;. Apelul unei metode virtuale folosind o referință de alt tip decât al clasei din care face parte obiectul, va apela metoda corespunzătoare obiectului în sine, nu cea care aparține tipului referinței.&lt;br /&gt;
&lt;br /&gt;
== Exemplu ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C++&amp;quot; line highlight=&amp;quot;15,39&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class Animal {&lt;br /&gt;
    std::string mName;&lt;br /&gt;
    std::string mColor;&lt;br /&gt;
    int mAge;&lt;br /&gt;
protected:&lt;br /&gt;
    bool mHasFeathers;&lt;br /&gt;
&lt;br /&gt;
public:&lt;br /&gt;
    Animal(const std::string &amp;amp; name, const std::string &amp;amp; color) : mName(name), mColor(color) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    virtual void makeSound() const {&lt;br /&gt;
        printf(&amp;quot;Animal %s makes a sound!\n&amp;quot;, mName.c_str());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a getter method&lt;br /&gt;
    std::string getName() const {&lt;br /&gt;
        return mName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a setter method&lt;br /&gt;
    void setAge(int age) {&lt;br /&gt;
        if(age &amp;gt; 0) {&lt;br /&gt;
            mAge = age;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class Cat : public Animal {&lt;br /&gt;
    unsigned int mLives;&lt;br /&gt;
public:&lt;br /&gt;
    Cat(const std::string &amp;amp; name, const std::string &amp;amp; color) : Animal(name, color), mLives(9) {&lt;br /&gt;
        mHasFeathers = false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void makeSound() const override {&lt;br /&gt;
        printf(&amp;quot;Cat %s meows!\n&amp;quot;, getName().c_str());&lt;br /&gt;
    }&lt;br /&gt;
}; &lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    Animal animal(&amp;quot;Rex&amp;quot;, &amp;quot;black&amp;quot;);&lt;br /&gt;
    Cat cat(&amp;quot;Spot&amp;quot;, &amp;quot;tabby&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    Animal &amp;amp; animalRef = animal;&lt;br /&gt;
    Cat &amp;amp; catRef = cat;&lt;br /&gt;
    Animal &amp;amp; catRef2 = cat;&lt;br /&gt;
&lt;br /&gt;
    animalRef.makeSound();&lt;br /&gt;
    catRef.makeSound();&lt;br /&gt;
    catRef2.makeSound();&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ieșire:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Animal Rex makes a sound!&lt;br /&gt;
Cat Spot meows!&lt;br /&gt;
Cat Spot meows!&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;sfat&amp;quot;&amp;gt;&amp;lt;font color=&amp;quot;darkgreen&amp;quot;&amp;gt;Sfat:&amp;lt;/font&amp;gt; Când se suprascrie o metodă într-o clasă derivată, este recomandat să plasați înainte de acolada deschisă care implementează metoda cuvântul cheie &amp;lt;code&amp;gt;override&amp;lt;/code&amp;gt;. Deși acest lucru nu este obligatoriu, vă va avertiza printr-o eroare de compilare dacă suprascrierea nu se face corect (de exemplu dacă metoda din clasa de bază nu este declarată virtuală).&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Metode pur virtuale și clase abstracte =&lt;br /&gt;
&lt;br /&gt;
== Introducere ==&lt;br /&gt;
&lt;br /&gt;
În anumite situații, o metodă virtuală nu poate avea o implementare în clasa de bază, pentru că nu este cunoscut modul în care aceasta se comportă. În această situație, metoda poate fi definită ca fiind &amp;#039;&amp;#039;&amp;#039;pur virtuală&amp;#039;&amp;#039;&amp;#039;, adică o metodă fără implementare, dar care este totuși declarată în cadrul clasei. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;regula&amp;quot;&amp;gt;&amp;lt;font color=&amp;quot;#ff0000&amp;quot;&amp;gt;Atenție: &amp;lt;/font&amp;gt;Dacă o clasă conține cel puțin o metodă pur virtuală aceasta se numește &amp;#039;&amp;#039;&amp;#039;clasă abstractă&amp;#039;&amp;#039;&amp;#039; și nu poate fi instanțiată.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dacă am crea un obiect de tipul respectiv, atunci nu am putea apela metoda pur virtuală pentru că implementarea aceasteia lipsește. Clasele abstracte se pot folosi numai pentru a fi extinse, și metodele pur virtuale trebuie suprascrise în clasele derivate. Dacă cel puțin una din metodele pur virtuale nu este suprascrisă, atunci clasa derivată este la rândul ei abstractă.&lt;br /&gt;
&lt;br /&gt;
== Exemplu ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C++&amp;quot; line highlight=&amp;quot;24,45&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class Animal {&lt;br /&gt;
    std::string mName;&lt;br /&gt;
    std::string mColor;&lt;br /&gt;
    int mAge;&lt;br /&gt;
protected:&lt;br /&gt;
    bool mHasFeathers;&lt;br /&gt;
&lt;br /&gt;
public:&lt;br /&gt;
    Animal(const std::string &amp;amp; name, const std::string &amp;amp; color) : mName(name), mColor(color) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    virtual void makeSound() const {&lt;br /&gt;
        printf(&amp;quot;Animal %s makes a sound!\n&amp;quot;, mName.c_str());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // this is a getter method&lt;br /&gt;
    std::string getName() const {&lt;br /&gt;
        return mName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    virtual int getNumberOfLegs() const = 0;&lt;br /&gt;
&lt;br /&gt;
    // this is a setter method&lt;br /&gt;
    void setAge(int age) {&lt;br /&gt;
        if(age &amp;gt; 0) {&lt;br /&gt;
            mAge = age;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class Cat : public Animal {&lt;br /&gt;
    unsigned int mLives;&lt;br /&gt;
public:&lt;br /&gt;
    Cat(const std::string &amp;amp; name, const std::string &amp;amp; color) : Animal(name, color), mLives(9) {&lt;br /&gt;
        mHasFeathers = false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void makeSound() const override {&lt;br /&gt;
        printf(&amp;quot;Cat %s meows!\n&amp;quot;, getName().c_str());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    int getNumberOfLegs() const override {&lt;br /&gt;
        return 4;&lt;br /&gt;
    }&lt;br /&gt;
}; &lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    Animal animal(&amp;quot;Rex&amp;quot;, &amp;quot;black&amp;quot;); // eroare de compilare, Animal este clasa abstracta&lt;br /&gt;
    &lt;br /&gt;
    Cat cat(&amp;quot;Spot&amp;quot;, &amp;quot;tabby&amp;quot;);&lt;br /&gt;
    Cat &amp;amp; catRef = cat;&lt;br /&gt;
    Animal &amp;amp; catRef2 = cat;&lt;br /&gt;
&lt;br /&gt;
    catRef.makeSound();&lt;br /&gt;
    catRef2.makeSound();&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rhobincu</name></author>
	</entry>
</feed>