From e44e1f8e0005e948d062d4660886a48ad95d9042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83dulescu?= Date: Tue, 17 Mar 2026 21:17:40 +0200 Subject: [PATCH] Am rezolvat exercitiile de la markdown. --- Makefile | 12 + README.md | 454 +++++++++++++++++++++++++- dynamic-linking.ro.md | 13 +- gnumake/Makefile | 5 + gnumake/clean | 1 + gnumake/custom/greeting.c | 16 + gnumake/custom/header.h | 5 + gnumake/custom/part1.c | 30 ++ gnumake/custom/part2.c | 30 ++ gnumake/example.c | 6 + helloworld.md | 253 ++++++++++++++ hobby.md | 60 ++++ makefiles/rezumat | 112 ------- makefiles/makefile1 => pitch/example1 | 0 makefiles/makefile2 => pitch/example2 | 10 +- 15 files changed, 870 insertions(+), 137 deletions(-) create mode 100644 Makefile create mode 100644 gnumake/Makefile create mode 100644 gnumake/clean create mode 100644 gnumake/custom/greeting.c create mode 100644 gnumake/custom/header.h create mode 100644 gnumake/custom/part1.c create mode 100644 gnumake/custom/part2.c create mode 100644 gnumake/example.c create mode 100644 helloworld.md create mode 100644 hobby.md delete mode 100644 makefiles/rezumat rename makefiles/makefile1 => pitch/example1 (100%) rename makefiles/makefile2 => pitch/example2 (62%) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7653ff5 --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CFLAGS = -Wall -Wextra -O2 + +all: demo + +.PHONY: clean + +demo: helloworld/helloworld.c + $(CC) $(CFLAGS) -o $@ $^ + +clean: + rm demo diff --git a/README.md b/README.md index 9e7e187..5934730 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ # Markdown and Makefile Workshop This is a practical workshop about the syntax and the use of the [Markdown format](https://www.markdownguide.org/basic-syntax/) and of the [GNU make](https://www.gnu.org/software/make/manual/make.html) utility. -In particular, we will focus on the [GitHub Flavored Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax), used by GitHub. +The Markdown part of this workshop will focus on the [GitHub Flavored Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) version, used by GitHub. See the full specification of the GitHub Flavored Markdown [here](https://github.github.com/gfm/). > [!NOTE] > Markdown is not only used in GitHub / GitLab and other software development platforms, but also in chat message engines such as [Discord](https://discord.com/), note taking apps such as [HackMD](https://hackmd.io/) and wiki engines such as [MDwiki](https://mdwiki.info). > Parts of the Markdown syntax are also used on WhatsApp, MS Teams and other chat message engines, particularly for text formatting. -> Makefiles are used to efficiently build and debug software in all types of projects, from message applications to hypervisors and operating system modules. What makes them so special is the ability to create a chain of command between different Makefiles, which has the wonderful effect of modularization. +> Makefiles are used to efficiently build and debug software in all types of projects, from message applications to hypervisors and operating system modules. +> What makes them so special is the ability to create a chain of command between different Makefiles, which has the wonderful effect of modularization. ## Set Up @@ -57,7 +58,7 @@ Identify syntax aspects in the documentation for [GitHub Flavored Markdown](http See: - The use of `#`, `##`, `###` for section headings. -- The use of backticks for typewriter font, used for the names of files, functions, and +- The use of backticks for typewriter font, used for the names of files, functions, and - The use `-` and `\*` for unordered lists. - The use of `1.` for ordered lists. - The syntax used for links. @@ -252,6 +253,446 @@ Check the GitHub web view of the [upstream repository](https://github.com/rosedu After the pull request is merged, go to the same steps as above to clean your pull request. +## What is GNU Make? + +Make is a toolchain included in the GNU open-source software application collection that is used to set up and organise building, installing and cleaning procedures in a development repository. + +We will look at some examples from the open-source world. + +### This Repository + +Let's look at the file named `Makefile`: + +```console +cat Makefile +``` + +Although it does not have any file extension, it is basically a text file. +It may seem like a coincidence that the file we are using GNU make with is named Makefile, but this is actually a recommendation and a global standard between developers. + +If we look at this file more closely, we will see some syntax rules vital for a Makefile: + + - There are multiple rules that contain multiple lines indented with a tab, which are part of a so-called *recipe* + - Each rule starts with a name or a file, we will from now on call it a *target* + - After the colons there are one or more files, which are known as *prerequisites* + - At the beginning (but not exclusively) there are a couple of *variables* + +To see the effects of this file, run: + +```console +make demo +``` + +### Operating Systems (from Open Education Hub) + +Read the Makefile in the [Operating Systems (Open Education Hub / `cs-pub-ro`) repository](https://github.com/cs-pub-ro/operating-systems). +There are a couple of rules that build on top of each other, we will go over this concept later on. + +### KraftKit (from Unikraft) + +Read the Makefile in the [KraftKit repository](https://github.com/unikraft/kraftkit/tree/staging). +This file contains advanced syntax, so you should focus on variable definitions, the use of `.PHONY` and conditional blocks. + +## Building a Makefile + +In order to properly grasp how one writes a Makefile, we will discuss each step individually. +First, let's write our first rule! + +### Rules and recipes + +The main part of a Makefile are its rules and the recipes associated to each rule. +They abide by the following format: + +```console + ... : ... + + + ... +``` +> [!NOTE] +> All recipe commands must be indented using tab! +> This is how Make knows a text line belongs to a specific recipe. +> Equally important is that a rule may contain more than one target or more than one prerequisite (even zero prerequisites!), depending on the build flow of the application. + +We will start by writing our first build rule. +In order to do that, go to the `gnumake` folder. +You will find there an empty Makefile waiting for you. + +You will also find some source files containing code written in C. +Those will be our *prerequisites* for the length of this demo, given that we are building our application from them. +We will build `example.c`. + +Based on what we know, in order to obtain our binary, we must begin with `example`, as this is our target, our end goal. +To build it, we need `example.c` and a C compiler (i.e. `gcc`) to run `gcc -o example example.c`. +Now we can build our rule: + +```make +example: example.c + gcc -o example example.c +``` + +In order to run any rule from a Makefile, the usual command is: + +```console +make +``` + +If a rule has more than one target, you can choose any target to run the same recipe. +Run `make example` and execute the freshly-made application. + +Congratulations, you wrote your first Make rule! + +### Cleanup using Make + +There are moments when one may want to delete the products of a build process, which is widely known as *cleaning* our repository. +This is usually done to eliminate parasite effects of old binaries or to clear up the structure of the working directory. + +Make proposes a standard rule named `clean`, which is responsible for eliminating all byproducts of our source files. +There is a catch however; what could be the target of such rule? +The answer is: none. +It does not have any prerequisites either. + +#### .PHONY + +Some targets are not representing any files in our working directory, they are just names, tags for our recipes. +Rules that have such targets are categorised as *phony* because they can be misleading for Make. +For example, let's say we have this rule: + +```make +clean: + rm example +``` + +Write it in the Makefile and see if it does anything. + +Why does Make stop execution of this rule? +Well, there is a file in our working directory named `clean` and our rule does not have any prerequisites. +That means, there isn't anything that can change the file named `clean`, so Make will waste time by trying to build our target again and stops. +This is the default behaviour of the toolchain. + +How do we fix it? +We tell Make that the target of this rule is merely a name, not an actual file. +That way, Make will ignore the file and run the rule every time we request it. +This is how it should look: + +```make +.PHONY: clean + +clean: + rm example +``` + +There can be multiple rules labeled as phony in a single statement; +they are just mentioned and separed with a single space. + +This should be the final result: + +```make +example: example.c + gcc -o example example.c + +.PHONY: clean + +clean: + rm example +``` + +**Well done, you just built your first Makefile!** + +## Submit your first Makefile + +Submit the [`Makefile`](gnumake/Makefile) from the `gnumake` folder of this workshop. +Make sure you have implemented all the rules described above. + +Follow the instructions above to create the pull request. +Make sure you have good commit messages and a good pull request description. + +Target the pull request **to** your assigned branch. + +Ask the instructors to review your pull request. +Make updates as required. +Have your pull request approved and merged on top of your assigned branch. + +Check the GitHub web view of the [upstream repository](https://github.com/rosedu/workshop-markdown) for your assigned branch. +Click on the button with `main` (the branch button) and select your branch. + +Check the rules of the [`Makefile`](gnumake/Makefile) and see if the recipes are working correctly. + +### Clean Up After Pull Request + +After the pull request is merged, clean up your work environment. +That is: + +1. Go the pull request GitHub view and delete the remote branch. + +1. Remove the reference to the remove branch in your clone: + + ```console + git remote prune origin + ``` + +1. Checkout the `main` branch: + + ```console + git checkout main + ``` + +1. Remove the local branch that you used for creating the pull request. + It has the same name as the one you remote branch you removed above: + + ```console + git branch -D + ``` + +1. Fetch the updates for your assigned branch. + Your assigned branch is now updated after the pull request was merged: + + ```console + git fetch upstream + git checkout + git rebase upstream/ + ``` + +1. Check the branch: + + ```console + git log + ``` + +## Bits and pieces of Makefiles + +Makefiles are written using the following structures: + +- **Explicit Rules:** targets and prerequisites are mentioned and a recipe is clearly laid out; + +- **Implicit Rules:** they apply to classes of files and describe a target's dependency of a similarly-named source file; + +- **Variables:** it associates a tag / name to a string of text; + +- **Directives:** special instructions to be carried out by Make as it reads the Makefile, for example reading another Makefile, or ignoring specific parts of a Makefile based on the value of evaluated variables; + +- **Comments:** starting with `#`, can be continued on the next line if we add at the end of the line `\`; +backslash can also be used to break up long commands in order to improve readability; + +The first rule written in the Makefile is the default rule that runs when we use `make`. +When running a rule, if there is a prerequisite that is +the target of another rule it will run that before. +Think of it as a depth-first search on graphs, +where the nodes are the rules and the vertices are the +dependencies on one another! + +Using these components, engineers can build massive projects without wrapping their head with compiler commands and dependencies. +Without further ado, let's get into using these! + +### Variables + +Variables are useful in multiple scenarios. +Let's say that someone wants to change the compiler that is being used inside the Makefile. +Changing hundreds of lines of recipes is gruesome, +so instead we use a variable that contains the compiler's name +to allow easier update and refinement of various instructions. +Here is an example: + +```make +example_variable = src1.c src2.c +# when expanded with $(example_variable) +# it will be replaced by "src1.c src2.c" + +CC = gcc + +example: example.c + $(CC) -o example example.c + # Make is therefore running + # "gcc -o example example.c" +``` + +Variables can also be used to reference targets and prerequisites in an easier manner. + +### Wildcards and automatic variables + +Wildcards are characters that expand automatically to predefined values. +They have the same meaning as the ones in Bash. +The usual suspects are `*`, `~` and `?`. +We will describe them below: + + - `*` is a placeholder for zero or more characters; + - `~` is a placeholder for the home directory of the current user; + - `?` is a placeholder for exactly one character. + +Automatic variables are pairs of characters that start with `$`. +Their values vary depending on the executed rule and other factors: + + - `$^` is replaced with all prerequisites of a rule automatically at recipe execution; + - `$@` is replaced with the targets of the rule automatically at execution, even if the rule is declared as .PHONY. + It basically replaces character by character this sequence with the targets sequence. + - `$<` is replaced with the first prerequisite automatically. + +Let's see an example to clear things up! +In the folder with the Makefile given below, +there are two files, namely `example1.c` and `example2.c`. + +```make +example: *.c + gcc -o $@ $^ + +.PHONY: clean distclean + +clean: + rm example + +# this deletes even the source files +# given that this is an example, it is a niche case +# in real world applications, this would never be a rule!!! + +distclean: clean + rm example?.c + +# also, the dependency on clean means that distclean runs it before running its own recipe! +``` + +### Conditionals + +Conditional blocks are structured very similarly with the if-else statement in C, +where the evaluation statement is always checking something with regard to the contents of a variable. +Here is an example of a simple if statement: + +```make +# CC could also be set to msvc, clang, mingw et cetera... +CC = gcc + +foo: foo.c +ifeq ($(CC), gcc) + $(CC) -o foo $^ +else + echo "Warning! The program logic was written with the particularities of gcc in mind. Stopping recipe execution..." +endif +``` + +We can use the following operators: + - `ifeq`: checks if the contents of the variable are *equal* to the value given inside the statement; + - `ifneq`: checks if the contents of the variable are *different* from the value given inside the statement; + - `ifdef`: checks whether a variable with a specific name is defined; + - `ifndef`: checks wheter a variable with a specific name is *NOT* defined; + +### Functions + +Functions are useful to process text inside a Makefile. +The results of these functions can be used to process files or alter execution flow. +One of the more important functions is `shell`, because it communicates with the outer environment. +In order to use it and save its results to a variable, we can use the following structure: + +```make +pwd_files := $(shell ls) +``` + +It is also important to mention that the `:=` operator expands variables directly +referenced before setting its value. + +There are multiple functions that can be used. +You can check them out in the [GNU Make documentation](https://www.gnu.org/software/make/manual/make.html#Text-Functions). + +You may need to create a new string of text containing forbidden characters, like braces, commas, spaces and so on. +To circumvent the fact that Make does not support escaping characters with `\`, you can use the following logic: + +```make +comma:= , +empty:= +space:= $(empty) $(empty) +foo:= a b c +bar:= $(subst $(space),$(comma),$(foo)) +# bar is now ‘a,b,c’. +``` + +After that, you can call your new function using `$( ,,...)`. +The function result will be expanded in-place, exactly like a variable! + +## Good Makefile Practices + +There are several recommendations regarding the naming of Makefile rules and how they should behave. +Not only that, but Makefiles should usually bear a name that will be automatically recognised by Make. + +### Makefile naming convention + +Based on how Make is implemented in the GNU library, +in order to run a `make` command without explicitly specifying +the Makefile's location one should name it: + +- "GNUmakefile" +- "makefile" +- "Makefile" + +The first is rarely met and developers usually opt for the last 2 options. +This is the order in which Make looks for Makefiles in the current working directory. +When it finds a Makefile with one of these names, +it stops searching and starts executing recipes. + +> [!NOTE] +> Makefiles do not bear any file extension! + +> [!NOTE] +> We do not recommend naming Makefiles in any other way except those recognised automatically by Make. +> It can represent a serious obstacle for developers that do not know the actual name of the project's Makefile. +> All being said, if you need to use a specific file that is not automatically picked, one can use the `-f ` option. + +### Multi-thread execution + +Make supports executing multiple recipes simulatenously. +This is achieved using the `-j ` option and it is usually +the norm to insert the number of logical processors / threads your machine has. +On Linux / macOS, this usually is `-j $(nproc)`. + +If no thread limit is given, Make will create as many threads as it needs, +usually leading to getting your Operating System stuck with too many threads. + +### Multi-file structure + +Make supports fragmenting rules into multiple Makefiles, +creating something similar to an arborescent structure containing +primary and secondary Makefiles. This is achieved by using: + +`include ...` + +Make will read these Makefiles first before starting to execute +any rule requested by the user. + +## Your Turn + +Create a Makefile in the `gnumake/custom` folder that follows the rules listed below. +Use as many Make features as possible. +If you believe you need additional source files, you may also add them to the pull request. + +Your Makefile must offer the following features: + +- an all rule (at the beginning of the file) +- a clean rule +- comments regarding the behaviour and result of each rule +- declaration of all phony rules +- a rule for `greeting.c` +- a rule for compiling `part1.c` and `part2.c` +- two variables (for filenames, compilers or flags) +- a conditional block +- a function +- one of the rules should be in another Makefile and included / referenced in the main Makefile! + +Be careful! `part1.c`, `part2.c` and `header.h` should be used in the same command! + +Submit the Makefile as part of a pull request. + +Follow the instructions above to create the pull request. +Make sure you have good commit messages and a good pull request description. + +Target the pull request **to** your assigned branch. + +Ask the instructors to review your pull request. +Make updates as required. +Have your pull request approved and merged on top of your assigned branch. + +Check the GitHub web view of the [upstream repository](https://github.com/rosedu/workshop-markdown) for your assigned branch. + +### Clean Up After Pull Request + +After the pull request is merged, go to the same steps as above to clean your pull request. + ## GitHub Profile Page GitHub provides you to option to have a GitHub profile page, that you can use as a form of open source CV / portfolio. @@ -302,13 +743,6 @@ Follow the steps: Push commits to the GitHub remote repository. Now check your resulting profile page on your GitHub page. -## Use of GNU make in public projects - -We will study different implementations of Makefiles across multiple projects to get a feel of its purpose and strengths. - -### This Repository - - ## Create a Website with GitHub and Markdown We can use the contents of a GitHub repository, written with Markdown, to create a website. diff --git a/dynamic-linking.ro.md b/dynamic-linking.ro.md index 3630d63..041cd09 100644 --- a/dynamic-linking.ro.md +++ b/dynamic-linking.ro.md @@ -14,7 +14,6 @@ Pentru aceasta, am renunțat la argumentul `-static` folosit la linkare. Pentru acest exemplu, obținem un singur executabil `main`, din legarea statică cu biblioteca `libinc.a` și legarea dinamică cu biblioteca standard C. Similar exemplului din directorul `05-static/, folosim comanda `make` pentru a obține executabilul `main`: - ```console [..]/06-dynamic$ ls inc.c inc.h main.c Makefile @@ -39,14 +38,13 @@ main: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically link [..]/06-dynamic$ file ../05-static/main ../05-static/main: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=60adf8390374c898998c0b713a8b1ea0c255af38, not stripped -`` +``` Fișierul executabil `main` obținut prin linkare dinamică are un comportament identic fișierului executabil `main` obținut prin linkare statică. Observăm că dimensiunea sa este mult mai redusă: ocupă `7 KB` comparativ cu `600 KB` cât avea varianta sa statică. De asemenea, folosind utilitarul `file`, aflăm că este executabil obținut prin linkare dinamică (*dynamically linked*), în vreme cel obținut în exemplul anterior este executabil obținut prin linkare statică (*statically linked). Investigăm simbolurile executabilului: - ```console [..]/06-dynamic$ nm main [...] @@ -76,8 +74,7 @@ La încărcare, o altă componentă software a sistemului, loaderul / linkerul d - parcurgerea simbolurilor nedefinite din cadrul fișierului executabil, localizarea lor în biblioteca înacarcată dinamic și relocarea lor în executabilul încărcat în memorie Putem investiga bibliotecile dinamice folosite de un executabil prin intermediul utilitarului `ldd`: - -``console +```console [..]/06-dynamic$ ldd main linux-gate.so.1 (0xf7f97000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d8a000) @@ -111,7 +108,6 @@ Diferența este că acum, folosim linkare dinamică în loc de linkare statică Pentru aceasta, construim fișierul bibliotecă partajată `libinc.so`, în locul fișierului bibliotecă statică `libibc.a`. Similar exemplului din directorul `06-dynamic/`, folosim comanda `make` pentru a obține executabilul `main`: - ```console [..]/07-dynlib$ ls inc.c inc.h main.c Makefile @@ -146,7 +142,6 @@ Executabilul obținut are dimensiunea în jur de `7 KB` puțin mai mică decât Diferența cea mai mare este că, acum, simbolurile din biblioteca `libinc.so` (`increment`, `init`, `print`, `read`) sunt nerezolvate. Dacă încercăm lansarea în execuție a executabilului, observăm că primim o eroare: - ```console [..]/07-dynlib$ ./main ./main: error while loading shared libraries: libinc.so: cannot open shared object file: No such file or directory @@ -156,7 +151,6 @@ Eroarea spune că nu poate localiza biblioteca `libinc.so` la încărcare (*load Este deci, o eroare de loader. O eroare similară obținem dacă folosim utilitarul `ldd`: - ```console [..]/07-dynlib$ ldd ./main linux-gate.so.1 (0xf7f9f000) @@ -172,7 +166,6 @@ Loaderul are definită calea unde să caute biblioteca standard C (`/lib/i386-li Ca să precizăm loaderului calea către bibliotecă, o cale simplă, de test, este folosirea variabilei de mediu `LD_LIBRARY_PATH`, pe care o inițializăm la directorul curent (`.` - *dot*). Odată folosită variabila de mediu `LD_LIBRARY_PATH`, lansarea în execuție a executabilului va funcționa, la fel și folosirea `ldd`: - ```console [..]/07-dynlib$ LD_LIBRARY_PATH=. ldd ./main linux-gate.so.1 (0xf7eda000) @@ -186,4 +179,4 @@ num_items: 1 Variabila de mediu `LD_LIBRARY_PATH` pentru loader este echivalentul opțiunii `-L` în comanda de linkare: precizează directoarele în care să fie căutate biblioteci pentru a fi încărcate, respectiv linkate. Folosirea variabilei de mediu `LD_LIBRARY_PATH` este recomandată pentru teste. -Pentru o folosire robustă, există alte mijloace de precizare a căilor de căutare a bibliotecilor partajate, documentate în (pagina de manual a loaderului / linkerului dinamic)(https://man7.org/linux/man-pages/man8/ld.so.8.html#DESCRIPTION). +Pentru o folosire robustă, există alte mijloace de precizare a căilor de căutare a bibliotecilor partajate, documentate în [pagina de manual a loaderului / linkerului dinamic](https://man7.org/linux/man-pages/man8/ld.so.8.html#DESCRIPTION). \ No newline at end of file diff --git a/gnumake/Makefile b/gnumake/Makefile new file mode 100644 index 0000000..5f5e31b --- /dev/null +++ b/gnumake/Makefile @@ -0,0 +1,5 @@ +# Extra tip: +# Comments in Makefiles start with '#' and stretch +# to the end of the line! + +# Start writing below this line... diff --git a/gnumake/clean b/gnumake/clean new file mode 100644 index 0000000..574b188 --- /dev/null +++ b/gnumake/clean @@ -0,0 +1 @@ +Do not modify the contents of this file. It's used to the demonstrate the `clean` rule. diff --git a/gnumake/custom/greeting.c b/gnumake/custom/greeting.c new file mode 100644 index 0000000..b5befef --- /dev/null +++ b/gnumake/custom/greeting.c @@ -0,0 +1,16 @@ +#include + +int main(void) { + printf("What's your name?\n"); + char *name = calloc(101, sizeof(char)); + if (name == NULL) { + printf("calloc() failed; exiting...\n"); + return -1; + } + + fgets(name, 101, stdin); + printf("Greetings, %s!\n", name); + + free(name); + return 0; +} diff --git a/gnumake/custom/header.h b/gnumake/custom/header.h new file mode 100644 index 0000000..f692ccb --- /dev/null +++ b/gnumake/custom/header.h @@ -0,0 +1,5 @@ +#include +#include +#include + +char* reply(char *initial); diff --git a/gnumake/custom/part1.c b/gnumake/custom/part1.c new file mode 100644 index 0000000..a53cc68 --- /dev/null +++ b/gnumake/custom/part1.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include "header.h" + +int main(void) { + char *mesg = calloc(101, sizeof(char)); + if (mesg == NULL) { + goto error; + } + + printf("Send a \"ping\" to get a pong;\n"); + printf("Or send something else and you get wrong!\n"); + fgets(mesg, 101, stdin); + + char *answer = reply(mesg); + if (answer == NULL) { + goto error; + } + + printf("%s\n", answer); + + free(mesg); + free(answer); + return 0; + +error: + printf("calloc() failed; exiting...\n"); + return -1; +} diff --git a/gnumake/custom/part2.c b/gnumake/custom/part2.c new file mode 100644 index 0000000..2840945 --- /dev/null +++ b/gnumake/custom/part2.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include "header.h" + +char* reply(char *initial) { + char *result = NULL; + + if (strcmp(initial, "ping") == 0) { + result = calloc(5, sizeof(char)); + if (result == NULL) { + goto error; + } + + strcpy(result, "pong"); + } else { + result = calloc(11, sizeof(char)); + if (result == NULL) { + goto error; + } + + strcpy(result, "Try again!"); + } + + return result; + +error: + printf("calloc() failed; exiting..."); + return NULL; +} diff --git a/gnumake/example.c b/gnumake/example.c new file mode 100644 index 0000000..6dd92b0 --- /dev/null +++ b/gnumake/example.c @@ -0,0 +1,6 @@ +#include + +int main(void) { + printf("Good job! You just built a binary with Make!"); + return 0; +} diff --git a/helloworld.md b/helloworld.md new file mode 100644 index 0000000..1abf6cb --- /dev/null +++ b/helloworld.md @@ -0,0 +1,253 @@ +# Helloworld Programs + +![Hello, World!](helloworld.png) + +We list below Helloworld programs for different programming languages, i.e. programs that print "Hello, World!". The specified compiler or interpreter is required for each programming languages. + +The table below summarizes the programs: + +| Language | Language (Spec) Site | Section | Build / Run Toolchain | Debian / Ubuntu Packages | +|----------|---------------------|---------|-----------------------|--------------------------| +| C | [The Standard - C](https://www.open-std.org/jtc1/sc22/wg14/) | C | GCC | `build-essential` | +| C++ | [The Standard - C++](https://www.open-std.org/jtc1/sc22/wg21/) | C++ | GCC / G++ | `build-essential`, `g++` | +| Dlang | [D Programming Language: Home](https://dlang.org/) | Dlang | GCC / GDC | `build-essential`, `gdc` | +| Go | [The Go Programming Language](https://go.dev/) | Go | Go | `golang` | +| Rust | [Rust Programming Language](https://www.rust-lang.org/) | Rust | Rust (Crate) | `rustlang` | +| Java | [Java Programming Language](https://www.java.com/) | Java | JDK | `openjdk-17-jdk` | +| x86_64 assembly | [x86 and amd64 instruction reference](https://www.felixcloutier.com/x86/) | x86_64 Assembly | GCC / GAS | `build-essential` | +| ARM64 assembly | [Arm A64 Instruction Set Architecture](https://developer.arm.com/documentation/ddi0596/latest) | ARM64 Assembly | GCC / GAS (AArch64) | `build-essential` | +| Bash | [Bash Reference Manual](https://www.gnu.org/software/bash/manual/bash.html) | Bash | Bash | `bash` | +| Python | [Welcome to Python.org](https://www.python.org/) | Python | Python | `python` | +| Ruby | [Ruby Programming Language](https://www.ruby-lang.org/) | Ruby | Ruby | `ruby` | +| PHP | [PHP: Hypertext Preprocessor](https://www.php.net/) | PHP | PHP | `php` | +| Perl | [The Perl Programming Language](https://www.perl.org/) | Perl | Perl | `perl` | +| Lua | [The Programming Language Lua](https://www.lua.org/) | Lua | Lua | `lua` | + +## C + +```c +#include + +int main(void) +{ + puts("Hello, World!"); + return 0; +} +``` + +Build with: + +``` +gcc -Wall -o helloworld helloworld.c +``` + +Run with: + +``` +./helloworld +``` + +## C++ + +```cpp +#include + +int main() +{ + std::cout << "Hello, World!" << std::endl; + return 0; +} +``` + +Build with: + +``` +g++ -Wall -o helloworld helloworld.cpp +``` + +Run with: + +``` +./helloworld +``` + +## Dlang + +```d +import std.stdio; + +void main() +{ + writeln("Hello, World!"); +} +``` + +Build with: + +``` +gdc -Wall -o helloworld helloworld.cpp +``` + +Run with: + +``` +./helloworld +``` + +## Go + +```go +package main + +import "fmt" + +func main() { + fmt.Println("Hello, World!") +} +``` + +Build and run with: + +``` +go run helloworld.go +``` + +## Rust + +```rust +fn main() { + println!("Hello, World"); +} +``` + +Build with: + +``` +rustc hello.rs +``` + +Run with: + +``` +./helloworld +``` + +## Java + +```java +public class HelloWorld { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} +``` + +Build with: + +``` +javac HelloWorld.java +``` + +Run with: + +``` +java HelloWorld +``` + +## x86_64 Assembly + +TODO + +Build with: + +TODO + +Run with: + +``` +./helloworld +``` + +## ARM64 Assembly + +TODO + +Run with: + +``` +./helloworld +``` + +## Bash + +```bash +echo "Hello, World!" +``` + +Run with: + +``` +bash helloworld.sh +``` + +## Python + +```python +print("Hello, World!") +``` + +Run with: + +``` +python helloworld.py +``` + +## Ruby + +```ruby +puts "Hello, World!" +``` + +Run with: + +``` +ruby helloworld.rb +``` + +## PHP + +```php + +``` + +Run with: + +``` +./helloworld +``` + +## Perl + +```perl +print("Hello, World!\n") +``` + +Run with: + +``` +perl helloworld.pl +``` + +## Lua + +```lua +print("Hello, World!") +``` + +Run with: + +``` +lua helloworld.lua +``` \ No newline at end of file diff --git a/hobby.md b/hobby.md new file mode 100644 index 0000000..a69d069 --- /dev/null +++ b/hobby.md @@ -0,0 +1,60 @@ +# Desen și Pictură 🎨 + +## Despre acest hobby + +Desenul și pictura sunt două dintre cele mai vechi forme de expresie artistică ale omenirii. +Fie că folosești un creion simplu sau culori acrilice, poți transforma o foaie albă într-o operă de artă. + +![Painting](https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/402px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg) + +## Tehnici populare + +Există multe tehnici pe care le poți folosi, fiecare cu stilul ei unic: + +- Desen în creion +- Acuarelă +- Acrilic +- Ulei +- Cărbune +- Pastel + +## Cum să începi pictura în acuarelă + +1. Cumpără un set de bază de acuarele și câteva pensule +2. Alege o hârtie specială pentru acuarelă (minim 200g/m²) +3. Umezește hârtia înainte de a aplica culoarea +4. Începe cu tonuri deschise și adaugă treptat culori mai închise +5. Lasă fiecare strat să se usuce înainte de a adăuga altul + +## Materiale de bază + +| Material | Utilizare | Preț aproximativ | +|----------|-----------|-----------------| +| Creion HB | Schițe și desen | ~5 RON | +| Acuarele (set 12) | Pictură pe hârtie | ~30 RON | +| Acrilice (set 6) | Pictură pe pânză | ~50 RON | +| Pensule (set) | Aplicare culoare | ~20 RON | +| Bloc desen A4 | Suport pentru desen | ~15 RON | + +## Un script simplu pentru generarea paletei de culori RGB + +```python +# Generează o paletă simplă de culori primare +culori = { + "Roșu": (255, 0, 0), + "Galben": (255, 255, 0), + "Albastru": (0, 0, 255), + "Verde": (0, 255, 0), + "Alb": (255, 255, 255), + "Negru": (0, 0, 0), +} + +for nume, (r, g, b) in culori.items(): + print(f"{nume}: RGB({r}, {g}, {b})") +``` + +## Resurse utile + +Pentru inspirație și tutoriale, îți recomand [Proko](https://www.proko.com), un site cu lecții gratuite de desen și anatomie artistică. 🚀 + +> "Every artist was first an amateur." – Ralph Waldo Emerson \ No newline at end of file diff --git a/makefiles/rezumat b/makefiles/rezumat deleted file mode 100644 index 587b49e..0000000 --- a/makefiles/rezumat +++ /dev/null @@ -1,112 +0,0 @@ -Un makefile e format din reguli, reguli care sunt sub urmatoarea forma: -target ... : prerequisites ... - recipe - ... - ... - ... - -target e de obicei numele fisierului generat de un program (ex. executabile sau fisiere obiect), dar poate fi si numele actiunii pe care vrem sa o intreprindem (clean de exemplu). prerequisites sunt fisierule utilizate ca input pentru a crea target. recipe sunt actiunile pe care utilitarul make le intreprinde in cadrul unei reguli anume (atentie! este obligatoriu ca orice instructiune din recipe sa fie precedata de un tab). anumite reguli nu au nevoie de prerequisites (vezi clean, care face doar o actiune de delete). asadar, make tot ce face este sa urmeze niste reguli pe care noi le impunem printr-un asa-numit makefile, care contine pe larg un set de reguli. - -studiati regulile din `makefile1` si cum se compun una pe alta. pentru a crea executabilul, rulam `make`. pentru a curata folderul de lucru de fisiere obiect si executabile, folosim `make clean`. - -makefile-ul stie sa aplice selectiv anumite reguli, adica daca doua fisiere obiect din sapte ale unui executabil nu mai sunt de actualitate, le va recompila doar pe acelea, nu pe toate sapte, iar mai apoi executabilul daca asta i-a fost cerut. o sa vedem in exemplu ca daca am compilat programul si incercam imediat dupa sa compilam din nou, make ne va spune ca nu e nimic de facut. - -exista o regula standard pentru makefile-uri care se numeste clean, nu reprezinta un fisier, ci actiunea care este desfasurata. clean nu provine din nicio alta regula si nu ruleaza decat daca ii spunem utilitarului make in mod explicit asta. tintele care nu sunt backed de fisiere, cum este clean, se numesc tinte phony, vom vorbi mai tarziu in detaliu despre ele. - -primul target din makefile este target-ul default, care ruleaza atunci cand rulam doar make, fara alte argumente. in exemplu, make va incerca sa construiasca exec, insa fisierele obiect inca nu au fost verificate si sunt prerequisites, deci se duce la ele si dupa se ocupa de exec. comportamentul acesta se oglindeste pentru fiecare regula (seamana foarte tare cu o parcurgere in adancime, DFS). regulile care nu sunt prerequisites sunt ignorate / sarite. - -gnu make permite pe langa reguli si utilizarea variabilelor in cadrul unui makefile. in exemplul oferit mai devreme, am folosit objects pentru a evita greselile de scriere atunci cand vine vorba de mai multe obiecte. am creat variabila objects, care tine loc pentru toate fisierele de tip obiect, iar atunci cand vrem sa o folosim, utilizam structura $(). astfel putem asigura o mai mare usurinta in editarea fisierelor make si un numar mai mic de greseli atunci cand este creat sau editat. - -ar trebui investigat daca trebuie mentionat si comportamentul gnu make cand vine vorba de reguli implicite (vezi in documentatia oferita in workshop-markdow:/README.md daca are sens sa incarcam studentii cu asa ceva). - -punand clean in setul de reguli phony, devine explicit faptul ca regula clean nu are tinta niciun fisier, mai degraba este doar o denumire, iar daca adaugam o liniuta fix inainte de rm, make va continua sa execute comenzile din regula, chiar daca rm va da eroare (nu se aplica doar pentru rm, este doar dat ca exemplu). pentru a face utilitarul make sa ruleze comenzile din regula clean, va trebui sa rulam in terminal `make clean`. - - -makefile-urile sunt formate din reguli explicite si implicite, definitii de variabile, directive si comentarii, le vom explica in detaliu mai jos: - -- o regula explicita mentioneaza cand si cum reconstruieste unul sau mai multe fisiere cunoscute drept targets si are mai multe fisiere de care depinde, numite prerequisites si contine o "reteta" pentru a reconstrui tintele. - -- o regula implicita mentioneaza cand si cum reconstruieste o clasa de fisiere bazat pe numele lor. descrie cum o tinta depinde de un fisier cu un nume similar si ofera o reteta pentru a reconstrui tinta respectiva. ele nu fac scopul acestui workshop si exista multiple discutii daca ele ar trebui utilizate sau nu (prezinta un risc de ambiguitate cu privire la modul in care este construit un target). - -- o definitie de variabila este o linie care asociaza o eticheta unui string de caractere. - -- o directiva este o instructiune pe care make sa o faca in timp ce citeste makefile-ul, ele pot fi de obicei: citirea altui makefile, decizia de ignora bazat pe valorile unor variabile daca sa ignore sau sa foloseasca o parte a unui makefile (parti conditionale) sau definirea unei variabile dintr-un string multi-line - -- un comentariu, precedat tot timpul de '#', iar daca ne dorim ca acel comentariu sa continue pe linia urmatoare, la finalul liniei adaugam '\'. daca vrem sa folosim # in makefile, dar nu pentru marcarea unui comentariu, trebuie sa il "escapam" folosind structura "\#". daca make intalneste un # in mijlocul unei definitii de variabile sau unui apel de functie, nu il va trata ca marcaj al unui comentariu. comentariile pot fi plasate si la sfarsitul unei linii, fara ca # sa fie tratat ca facand parte din comanda sau din variabila. - -liniile foarte lungi pot fi sparte in mai multe linii folosind backslash ('\') pentru a creste gradul de lizibilitate al makefile-ului, care este convertit de gnu make automat intr-un spatiu la citirea fisierului, alipind inapoi liniile separate de backslash-uri. - -fisierele in care sunt puse regulile pentru make trebuie denumite intr-un mod specific. GNU make cauta mai intai in folderul de lucru fisierul "makefile" si apoi "Makefile". daca nu il gaseste, nu va face nimic. pot fi utilizate si alte denumiri pentru makefile, insa functionalitatea respectiva nu este recomandata in industrie si atunci nu face scopul acestui workshop. - -daca vrem sa construim o oarecare structura "arborescenta" de makefile-uri, putem folosi in partea incipienta a unui fisier comanda "include ", care va citi makefile-urile subordonate inainte de a continua citirea makefile-ului unde s-a intalnit cuvantul cheie include. - -mare grija la indentarea liniilor! liniile care incep cu un tab sunt considerate ca facand parte dintr-o reteta a unei reguli. - -exista mai multe caractere wildcard care pot usura compunerea unui makefile. acestea sunt '*', '?' si '[...]', le vom discuta mai in detaliu mai jos: - -- '*' tine loc pentru toate fisierele. de exemplu, daca spun ca o regula are drept prerequisites '*.c', asta inseamna ca toate fisierele al caror nume se termina in '.c' din directorul de lucru vor fi preluate drept necesare pentru acea regula. lista returnata de wildcard-ul * este sortata. - -- '~' tine loc pentru calea directorului home (are acelasi comportament ca '~' din bash). daca vrem sa prescurtam caile, putem spune de exemplu '~/bin' in loc de '/home/my_user/bin'. - -exista si asa-zise "automatic variables", cum ar fi '$^', '$@' si altele, le vom discuta in cele ce urmeaza: - -- '$^' este un inlocuitor pentru toate prerequisite-urile unei reguli, inlocuirea fiind facuta automat la executarea unei anumite reguli - -- '$@' este un inlocuitor pentru tinta regulei. atentie! daca regula are un nume abstract (sau phonynumit in GNU make), vom construi o tinta care are numele regulei, mare grija la utilizarea acestei variabile automate. - -- '$<' este un inlocuitor pentru primul obiect din prerequisites. de exemplu, daca am: -``` -foo.o: foo.c defs.h hack.h - gcc -c $< -o $@ -``` -va fi dat spre compilare doar foo.c, nu si headerele. - -target-urile phony sunt cele care nu au numele unui fisier, este mai degraba doar un nume pentru un set de instructiuni care trebuie executat cand se cere asta in mod explicit. exista doua motive pentru utilizarea unei astfel de tinte, evitarea unui conflict cu un fisier cu acelasi nume si imbunatatirea performantei. daca tintele phony nu sunt marcate explicit ca fiind phony (discutam mai tarziu putin despre cum facem asta), daca la un moment dat in folderul de lucru va aparea un fisier cu acelasi nume, regula nu va fi executata niciodata deoarece fisierul va fi considerat de actualitate. pentru a evita asta, folosim un marcator special: - -``` -.PHONY: clean -clean - rm *.o temp -``` - -pentru a folosi o variabila, folosim structura '$()' in retete sau in lista de target-uri sau prerequisites. - -in proiectele mai mari, atunci cand ne este indicat sa folosim comanda ```make -j ```, acel argument de dupa `-j` reprezinta numarul de job-uri, mai exact numarul de retete, care vor fi executate simultan. cu toate acestea, trebuie sa ne asiguram ca makefile-ul este bine scris, astfel incat paralelizarea task-urilor sa nu duca la o eroare, cum ar fi un fisier cautat care inca nu a fost construit de o alta regula. - -partile conditionale ale unui makefile sunt structurate ca un bloc if-else, unde conditia evaluata are mereu de-a face cu o variabila din makefile. - -``` -# in acest exemplu, presupunem ca variabila CC este setata de noi ca gcc, poate fi de asemenea clang, g++ et cetera -CC = gcc - -foo: foo.c -ifeq ($(CC), gcc) - $(CC) -o foo $^ -else - echo "Warning! The program logic was written with the particularities of gcc in mind. Stopping make foo rule..." -endif -``` - -pe langa ifeq, exista si ifneq, care in loc de `==`, face `!=`, mai exista si ifdef , care verifica daca o var este definita, dar si ifndef, care verifica daca variabila NU este definita, in acest caz intorcand true. - -GNU make intoarce 0 daca comanda make s-a incheiat cu succes, 2 daca in timpul citirii sau executarii apare o eroare, iar 1 este rezervat pentru flag-ul '-q' si make considera ca una dintre tinte nu mai este de actualitate. - -pentru a rula o regula specifica din makefile, rulam comanda `make `. mai jos este o lista de reguli standard care pot aparea in cadrul unui makefile. Atentie! aceste reguli nu sunt definite automat de catre GNU make, ele reprezinta doar niste conventii care sunt lasate in seama celui care scrie fisierului respectiv. - -- 'all' construieste toate target-urile top-level cunoscute makefile-ului; -- 'clean' sterge toate fisierele care sunt create in mod normal de make; -- 'mostlyclean' este asemanator cu 'clean', insa nu sterge fisierele a caror compilare ia foarte mult timp; -- 'distclean', 'realclean', 'clobber' sunt tinte care pot sau nu sa fie definite si de obicei au un comportament mai agresiv decat 'clean' (de exemplu, sterg si fisierele utilizate pentru configurarea procesului de constructie). -- 'install' copiaza fisierele executabile si fisierele auxiliare in folderele specifice pentru programul respectiv; -- 'print' listeaza fisierele sursa care s-au schimbat de la ultima rulare a lui make; -- 'test' ruleaza niste teste automate asupra executabilului construit de catre makefile; - -de asemenea, este o conventie generala ca fiecare makefile ar trebui sa inceapa cu linia -``` -SHELL =