getopt()#include <unistd.h> // needed for getopt()
#include <getopt.h> // needed for getopt_long()
// standard getopt, which can only parse single-character command-line arguments of type "-a" (with opt. argument)
int getopt(int argc, char * const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
// getopt_long, which allows for multiple-character command-line arguments of type "--arg"
int getopt_long(int argc, char *const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
// necessary for getopt_long:
struct option {
const char *name; // name of argument as string, e.g. "help" for --help
int has_arg; // no_argument, required_argument (if arg req) or optional_argument
int *flag; // if NULL, getopt_long() returns val, otherwise return 0 and store val at pointer address
int val; // a.k.a. shortname (abbrev.); value to return or to load into variable pointed to by flag address
};
// USEFUL: get program name with "basename(argv[0])" -> #define USAGE_FMT "%s [-v] [-f hexflag] [-i inputfile] [-o outputfile] [-h]"#include <unistd.h> // needed for getopt()
#include <getopt.h> // needed for getopt_long()
// standard getopt, which can only parse single-character command-line arguments of type "-a" (with opt. argument)
int getopt(int argc, char * const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
// getopt_long, which allows for multiple-character command-line arguments of type "--arg"
int getopt_long(int argc, char *const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
// necessary for getopt_long:
struct option {
const char *name; // name of argument as string, e.g. "help" for --help
int has_arg; // no_argument, required_argument (if arg req) or optional_argument
int *flag; // if NULL, getopt_long() returns val, otherwise return 0 and store val at pointer address
int val; // a.k.a. shortname (abbrev.); value to return or to load into variable pointed to by flag address
};
// USEFUL: get program name with "basename(argv[0])" -> #define USAGE_FMT "%s [-v] [-f hexflag] [-i inputfile] [-o outputfile] [-h]"getopt() standard definitions:
argc (argument count, int) and argv (argument vector, string array char** of arguments) are the same ones as passed to the main function- and is not exactly - or -- is considered an option element
- are option charactersgetopt() repeatedly successively returns each of the option characters from each of the option elements
getopt() should usually be called in a loop, where -1 indicates that no more options are present; see convention belowgetopt() automatically permutes argv so that all the non-options are at the end (?)
optstring is + or POSIXLY_CORRECT is set, then option processing stops as soon as a non-option argument is encounteredoptstring is -, then each nonoption argv-element is handled as if it were the argument of an option with character code 1-- forces an end of option-scanning regardless of the scanning modegetopt()-specific variables:
optind: index of next element to be processed in argv, initialized to 1 by the system and able to be reset by the caller to restart scanning of an argument vector (either same one as before or a new one)
optind stores the index in argv of the first element that is not an optionoptstring: string containing legitimate option characters (one-byte, printable ASCII character that is not space) that is not -, : or ;
:, it requires an argument, such that a pointer to the argument (a.k.a. the next string in argv) is placed in optarg (e.g. if a: is included, then for -a argument, optarg contains the string (!) argument)::) indicate that an option element has an optional argument
argv element (e.g. -oarg for -o), then it is returned in optarg, otherwise it is set to zerooptstring contains W;, then -W foo is treated as the long option --foo (for implementation reasons)optopt contains the erroneous option character following an error with return value ?opterr is set by default and results in getopt() printing an error message on standard error
optstring or missing option argumentopterr set): print error message, place erroneous option character in optopt and return ?opterr == 0: no error message printed, manual test needed for return value of ?optstring is :, then the function returns : to indicate a missing option argumentgetopt_long():
--help), specified in longopts (pointer to array of struct options)
{NULL, 0, NULL, 0})longindex is not NULL, it points to a variable which is set to the index of the long option relative to longoptsgetopt() Conventionsgetopt() in a loop to iterate through each command-line option and terminate loop once the function returns -1switch(c) to dispatch on the return value from getopt(), where for each case, usually, a variable is set that is later used in the programoptind until argc - 1// example code using getopt()
// source: https://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
int main(int argc, char** argv) {
int aFlag = 0;
int bFlag = 0;
char* cValue = NULL;
int index;
int c;
opterr = 0; // handle '?' case
// a and b don't take any arguments, whereas c does, as indicated by the ':'
while ((c = getopt(argc, argv, "abc:")) != -1) {
switch (c) {
case 'a':
aFlag = 1;
break;
case 'b':
bFlag = 1;
break;
case 'c':
cValue = optarg;
break;
case '?':
if (optopt == 'c') fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint(optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
return EXIT_FAILURE;
default:
abort();
}
}
printf("aflag = %d, bflag = %d, cvalue = %s\n", aFlag, bFlag, cValue);
for (index = optind; index < argc; index++) printf ("Non-option argument %s\n", argv[index]);
return EXIT_SUCCESS;
}
// example code using getopt()
// source: https://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
int main(int argc, char** argv) {
int aFlag = 0;
int bFlag = 0;
char* cValue = NULL;
int index;
int c;
opterr = 0; // handle '?' case
// a and b don't take any arguments, whereas c does, as indicated by the ':'
while ((c = getopt(argc, argv, "abc:")) != -1) {
switch (c) {
case 'a':
aFlag = 1;
break;
case 'b':
bFlag = 1;
break;
case 'c':
cValue = optarg;
break;
case '?':
if (optopt == 'c') fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint(optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
return EXIT_FAILURE;
default:
abort();
}
}
printf("aflag = %d, bflag = %d, cvalue = %s\n", aFlag, bFlag, cValue);
for (index = optind; index < argc; index++) printf ("Non-option argument %s\n", argv[index]);
return EXIT_SUCCESS;
}
// example code using getopt_long()
// source: https://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Option-Example.html
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
/* Flag set by ‘--verbose’. */
static int verbose_flag;
int main (int argc, char **argv) {
int c;
while (1) {
static struct option long_options[] =
{
/* These options set a flag. */
{"verbose", no_argument, &verbose_flag, 1},
{"brief", no_argument, &verbose_flag, 0},
/* These options don’t set a flag.
We distinguish them by their indices. */
{"add", no_argument, 0, 'a'},
{"append", no_argument, 0, 'b'},
{"delete", required_argument, 0, 'd'},
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 'f'},
{0, 0, 0, 0} // required!
};
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long (argc, argv, "abc:d:f:", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1) break;
switch (c) {
case 0: // long option found
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0) break;
printf("option %s", long_options[option_index].name);
if (optarg) printf (" with arg %s", optarg);
printf("\n");
break;
// standard getopt() procedure
case 'a':
puts("option -a\n");
break;
case 'b':
puts("option -b\n");
break;
case 'c':
printf("option -c with value `%s'\n", optarg);
break;
case 'd':
printf("option -d with value `%s'\n", optarg);
break;
case 'f':
printf("option -f with value `%s'\n", optarg);
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort();
}
}
/* Instead of reporting ‘--verbose’
and ‘--brief’ as they are encountered,
we report the final status resulting from them. */
if (verbose_flag) puts ("verbose flag is set");
/* Print any remaining command line arguments (not options). */
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc) printf ("%s ", argv[optind++]);
putchar ('\n');
}
return EXIT_SUCCESS;
}// example code using getopt_long()
// source: https://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Option-Example.html
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
/* Flag set by ‘--verbose’. */
static int verbose_flag;
int main (int argc, char **argv) {
int c;
while (1) {
static struct option long_options[] =
{
/* These options set a flag. */
{"verbose", no_argument, &verbose_flag, 1},
{"brief", no_argument, &verbose_flag, 0},
/* These options don’t set a flag.
We distinguish them by their indices. */
{"add", no_argument, 0, 'a'},
{"append", no_argument, 0, 'b'},
{"delete", required_argument, 0, 'd'},
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 'f'},
{0, 0, 0, 0} // required!
};
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long (argc, argv, "abc:d:f:", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1) break;
switch (c) {
case 0: // long option found
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0) break;
printf("option %s", long_options[option_index].name);
if (optarg) printf (" with arg %s", optarg);
printf("\n");
break;
// standard getopt() procedure
case 'a':
puts("option -a\n");
break;
case 'b':
puts("option -b\n");
break;
case 'c':
printf("option -c with value `%s'\n", optarg);
break;
case 'd':
printf("option -d with value `%s'\n", optarg);
break;
case 'f':
printf("option -f with value `%s'\n", optarg);
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort();
}
}
/* Instead of reporting ‘--verbose’
and ‘--brief’ as they are encountered,
we report the final status resulting from them. */
if (verbose_flag) puts ("verbose flag is set");
/* Print any remaining command line arguments (not options). */
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc) printf ("%s ", argv[optind++]);
putchar ('\n');
}
return EXIT_SUCCESS;
}#include <stdlib.h> // string -> integer (long, long long) long strtol(const char *restrict nptr, char **restrict endptr, int base); long long strtoll(const char *restrict nptr, char **restrict endptr, int base); // string -> floating point number (float, double, long double) double strtod(const char *restrict nptr, char **restrict endptr); float strtof(const char *restrict nptr, char **restrict endptr); long double strtold(const char *restrict nptr, char **restrict endptr);
#include <stdlib.h>
// string -> integer (long, long long)
long strtol(const char *restrict nptr, char **restrict endptr, int base);
long long strtoll(const char *restrict nptr, char **restrict endptr, int base);
// string -> floating point number (float, double, long double)
double strtod(const char *restrict nptr, char **restrict endptr);
float strtof(const char *restrict nptr, char **restrict endptr);
long double strtold(const char *restrict nptr, char **restrict endptr);
strtol() or strtoll()
nptr to a long integer value according to given base (between 2 and 36 inclusive or special value 0) until the first character that is not a valid digit in the given base is reached+ or -16 (i.e. hexadecimal), string may include optional prefix 0x or 0X0:
0x or 0X prefix, the number will be interpreted as a hex value (base 16)0, the number will be interpreted as an octal value (base 8)'a' == 'A' == 10)endptr is not NULL, the address of the first invalid character gets stored there
endptr = nptr and the function returns 0*nptr != '\0' && **endptr == '\0', then the entire string was validlong(L)LONG_MAX (OF) / (L)LONG_MIN (UF) and errno = ERANGE (both cases)
errno = 0 before the function call and check if errno != 0 afterwards to see if an actual over- or underflow occurederrno = EINVALstrtod() (or the other ones but who cares about those)
nptr to a double+ or - and then either…
., optionally followed by a decimal exponent E or e, followed by another optional + or -, followed by another non-empty sequence of decimal digits to indicate multiplication by a power of 10)0x or 0X followed by a non-empty sequence of hexadecimal digits)infinity / inf(case-insensitive)NaN (case-insensitive)endptr is not NULL, the address of the first invalid character gets stored there
endptr = nptr and the function returns 0.0*nptr != '\0' && **endptr == '\0', then the entire string was validdoubleHUGE_VAL and set errno = ERANGEDBL_MIN is returned and errno = ERANGE// example for strtol()
// source: man 3 strtol
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int base;
char *endptr, *str;
long val;
if (argc < 2) {
fprintf(stderr, "Usage: %s str [base]\n", argv[0]);
exit(EXIT_FAILURE);
}
str = argv[1];
base = (argc > 2) ? atoi(argv[2]) : 0; // ew, atoi
errno = 0; /* To distinguish success/failure after call */
val = strtol(str, &endptr, base);
/* Check for various possible errors. */
if (errno != 0) {
perror("strtol");
exit(EXIT_FAILURE);
}
if (endptr == str) {
fprintf(stderr, "No digits were found\n");
exit(EXIT_FAILURE);
}
/* If we got here, strtol() successfully parsed a number. */
printf("strtol() returned %ld\n", val);
if (*endptr != '\0') /* Not necessarily an error... */
printf("Further characters after number: \"%s\"\n", endptr);
exit(EXIT_SUCCESS);
}// example for strtol()
// source: man 3 strtol
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int base;
char *endptr, *str;
long val;
if (argc < 2) {
fprintf(stderr, "Usage: %s str [base]\n", argv[0]);
exit(EXIT_FAILURE);
}
str = argv[1];
base = (argc > 2) ? atoi(argv[2]) : 0; // ew, atoi
errno = 0; /* To distinguish success/failure after call */
val = strtol(str, &endptr, base);
/* Check for various possible errors. */
if (errno != 0) {
perror("strtol");
exit(EXIT_FAILURE);
}
if (endptr == str) {
fprintf(stderr, "No digits were found\n");
exit(EXIT_FAILURE);
}
/* If we got here, strtol() successfully parsed a number. */
printf("strtol() returned %ld\n", val);
if (*endptr != '\0') /* Not necessarily an error... */
printf("Further characters after number: \"%s\"\n", endptr);
exit(EXIT_SUCCESS);
}FILE* fopen(const char* restrict pathname, const char* restrict mode)
pathname: string that contains the path to the filemode: string beginning with one of the following sequences:
r: open file for reading, starting at beginning of filer+: open file for reading and writing, starting at beginning of filew: open and truncate to zero length / create file for writing, starting at beginning of filew+: open and truncate to zero length / create file for reading and writing, starting at beginning of filea: open for appending / create file for writing, starting at the end of the filea+: open for reading and appending / create file for reading and writing, starting at the end of the fileFILE pointer if successful, otherwise NULL and errno is setint fstat(int fd, struct stat *sb)
fileno(file)struct stat (e.g. struct stat statbuf; fstat(fileno(file), &statbuf))
st_dev: numeric ID of the device containing the filest_ino: the file’s inode number
st_dev and st_ino are enough to uniquely identify a file within the systemst_nlink: number of hard links to the filest_flags: flags enabled for the file, see chflagsst_atim: time when file data was last accessedst_mtim: time when file data was last modifiedst_ctim: time when file data was last changed (inode data modification)st_birthtim: time when inode was createdst_size: file size in bytesst_blksize: optimal I/O block size for filest_blocks: actual number of blocks allocated for file in 512-byte unitsst_uid: user ID of file’s ownerst_gid: group ID of filest_mode: status of file - can be tested using macros (0 if false, non-zero if true)
S_ISBLK(m): test for a block special fileS_ISCHR(m): test for a character special fileS_ISDIR(m): test for a directoryS_ISFIFO(m): test for a pipe or FIFO special fileS_ISLNK(m): test for a symbolic linkS_ISREG(m): test for a regular fileS_ISSOCK(m): test for a socketS_ISWHT(m): test for a whiteouterrno setsize_t fread(void* restrict ptr, size_t size, size_t nmemb, FILE* restrict stream)
nmemb bytes of data, each size bytes long, from the stream pointed to by stream, storing them at memory address ptrsize == 1); otherwise, short item count or zero (e.g. incomplete value)fread() does not distinguish between EoF and error, feof() and ferror() must be use to determine cause of errorsize_t fwrite(const void* restrict ptr, size_t size, size_t nmemb, FILE* restrict stream)
nmemb bytes of data, each size bytes long, to the stream pointed to by stream, reading bytes from memory address ptrsize == 1); otherwise, short item count or zero (e.g. incomplete value)fclose(FILE* fp)// example code
// source: ERA W07
// read contents of file to string
static char* read_file(const char* path) {
char* string = NULL;
FILE* file;
// check if file can be opened with reading permissions
if (!(file = fopen(path, "r"))) {
perror("Error opening file!");
return NULL;
}
// check if file statistics can be retrieved and stored in statbuf
struct stat statbuf;
if (fstat(fileno(file), &statbuf)) {
fprintf(stderr, "Error retrieving file stats!\n");
goto cleanup;
}
// check if file is regular and has valid size
if (!S_ISREG(statbuf.st_mode) || statbuf.st_size <= 0) {
fprintf(stderr, "Error processing file: Not a regular file or invalid size!\n");
goto cleanup;
}
// allocate sufficient bytes for file contents and extra null-byte to terminate string
if (!(string = malloc(statbuf.st_size + 1))) {
fprintf(stderr, "Error reading file: Could not allocate enough memory!\n");
goto cleanup;
}
// read contents and check if number of bytes read matches with file size in bytes
if (fread(string, 1, statbuf.st_size, file) != (size_t) statbuf.st_size) {
fprintf(stderr, "Error reading file!\n");
free(string);
string = NULL;
goto cleanup;
}
// append null byte
string[statbuf.st_size] = '\0';
// perform end-of-function / failure cleanup to prevent memory leak (!)
cleanup:
if (file) fclose(file);
// returns the string containing the data from the file or NULL if something went wrong
return string;
}
// write string to file
static void write_file(const char* path, const char* string) {
FILE* file;
// check if file can be opened with writing permissions
if (!(file = fopen(path, "w"))) {
perror("Error opening file!");
return;
}
// attempt to write contents and check if number of bytes written matches with file size in bytes
const size_t stringlength = strlen(string);
if (fwrite(string, 1, stringlen, file) != stringlen) {
fprintf(stderr, "Error writing to file!\n");
}
// once again, close the file when done!
fclose(file);
}
// example code
// source: ERA W07
// read contents of file to string
static char* read_file(const char* path) {
char* string = NULL;
FILE* file;
// check if file can be opened with reading permissions
if (!(file = fopen(path, "r"))) {
perror("Error opening file!");
return NULL;
}
// check if file statistics can be retrieved and stored in statbuf
struct stat statbuf;
if (fstat(fileno(file), &statbuf)) {
fprintf(stderr, "Error retrieving file stats!\n");
goto cleanup;
}
// check if file is regular and has valid size
if (!S_ISREG(statbuf.st_mode) || statbuf.st_size <= 0) {
fprintf(stderr, "Error processing file: Not a regular file or invalid size!\n");
goto cleanup;
}
// allocate sufficient bytes for file contents and extra null-byte to terminate string
if (!(string = malloc(statbuf.st_size + 1))) {
fprintf(stderr, "Error reading file: Could not allocate enough memory!\n");
goto cleanup;
}
// read contents and check if number of bytes read matches with file size in bytes
if (fread(string, 1, statbuf.st_size, file) != (size_t) statbuf.st_size) {
fprintf(stderr, "Error reading file!\n");
free(string);
string = NULL;
goto cleanup;
}
// append null byte
string[statbuf.st_size] = '\0';
// perform end-of-function / failure cleanup to prevent memory leak (!)
cleanup:
if (file) fclose(file);
// returns the string containing the data from the file or NULL if something went wrong
return string;
}
// write string to file
static void write_file(const char* path, const char* string) {
FILE* file;
// check if file can be opened with writing permissions
if (!(file = fopen(path, "w"))) {
perror("Error opening file!");
return;
}
// attempt to write contents and check if number of bytes written matches with file size in bytes
const size_t stringlength = strlen(string);
if (fwrite(string, 1, stringlen, file) != stringlen) {
fprintf(stderr, "Error writing to file!\n");
}
// once again, close the file when done!
fclose(file);
}
// some more example code
// source: wikipedia
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buffer[5];
FILE* fp = fopen("myfile", "rb");
if (fp == NULL) {
perror("Failed to open file \"myfile\"");
return EXIT_FAILURE;
}
for (int i = 0; i < 5; i++) {
int rc = getc(fp);
if (rc == EOF) {
fputs("An error occurred while reading the file.\n", stderr);
return EXIT_FAILURE;
}
buffer[i] = rc;
}
fclose(fp);
printf("The bytes read were... %02x %02x %02x %02x %02x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
return EXIT_SUCCESS;
}// some more example code
// source: wikipedia
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buffer[5];
FILE* fp = fopen("myfile", "rb");
if (fp == NULL) {
perror("Failed to open file \"myfile\"");
return EXIT_FAILURE;
}
for (int i = 0; i < 5; i++) {
int rc = getc(fp);
if (rc == EOF) {
fputs("An error occurred while reading the file.\n", stderr);
return EXIT_FAILURE;
}
buffer[i] = rc;
}
fclose(fp);
printf("The bytes read were... %02x %02x %02x %02x %02x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
return EXIT_SUCCESS;
}-std=c17-ggcc -o file.i -E file.cgcc -o file.S -S file.c -masm=intelgcov: --coverage-Wextra -Wall: essential-Wfloat-equal: useful because usually testing floating-point numbers for equality is bad-Wundef: warn if an uninitialized identifier is evaluated in an #if directive-Wshadow: warn whenever a local variable shadows another local variable, parameter or global variable or whenever a built-in function is shadowed-Wpointer-arith: warn if anything depends upon the size of a function or of void-Wcast-align: warn whenever a pointer is cast such that the required alignment of the target is increased (for example, warn if a char * is cast to an int * on machines where integers can only be accessed at two- or four-byte boundaries)-Wstrict-prototypes: warn if a function is declared or defined without specifying the argument types-Wstrict-overflow=5: warns about cases where the compiler optimizes based on the assumption that signed overflow does not occur (5 may be too strict)-Wwrite-strings: give string constants the type const char[length] so that copying the address of one into a non-const char * pointer will get a warning-Waggregate-return: warn if any functions that return structures or unions are defined or called-Wcast-qual: warn whenever a pointer is cast to remove a type qualifier from the target type (?)-Wswitch-default: warn whenever a switch statement does not have a default case (?)-Wswitch-enum: warn whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration (?)-Wconversion: warn for implicit conversions that may alter a value (?)-Wunreachable-code: warn if the compiler detects that code will never be executed (?)-g to generate debug info!info all-registersp $regp namep * namep/x namegdb ./file)main function in C (b main) (alternatively: set breakpoint for specific function, main is universal)layout regs shows the values loaded in each register at the top, the source file (C / ASM) in the middle and the terminal at the bottomr runs the programs runs the next line of the program$ gdb ./main $ b main $ layout regs $ r $ s
$ gdb ./main
$ b main
$ layout regs
$ r
$ s.intel_syntax noprefix // ensure intel syntax because intel rules and AT&T drools
.global function_name // make function externally visible to C program
.text
function_name:
...
ret.intel_syntax noprefix // ensure intel syntax because intel rules and AT&T drools
.global function_name // make function externally visible to C program
.text
function_name:
...
retmakefile is the default target$@: name of target$^: names of all prerequisites$<: name of first prerequisite# Standard Rule layout
# Target contains prerequisites "prerequisite1", "prerequisite2", ...
# These prerequisites can be source code files or other targets.
# The recipes are shell commands.
target : prerequisite1 prerequisite2 ...
recipe1
recipe2# Standard Rule layout
# Target contains prerequisites "prerequisite1", "prerequisite2", ...
# These prerequisites can be source code files or other targets.
# The recipes are shell commands.
target : prerequisite1 prerequisite2 ...
recipe1
recipe2# Layout of a typical Makefile to compile any C program
# Source: https://opensource.com/article/18/8/what-how-makefile
# Usage:
# make # compile all binary
# make clean # remove ALL binaries and objects
.PHONY = all clean # define phony targets all and clean
CC = gcc # compiler to use
LINKERFLAG = -lm # define flags to be used with GCC in a recipe
SRCS := $(wildcard *.c) # function for filenames: stores all files with extension .c
BINS := $(SRCS:%.c=%) # substitution reference: output files have same names as source files, without .c extension
# phony target all calls values in${BINS} as individual targets
all: ${BINS}
# Equivalent to:
# foo: foo.o
# @echo "Checking.."
# gcc -lm foo.o -o foo
%: %.o
@echo "Checking.."
${CC} ${LINKERFLAG} $< -o $@
# Equivalent to:
# foo.o: foo.c
# @echo "Creating object.."
# gcc -c foo.c
%.o: %.c
@echo "Creating object.."
${CC} -c $<
# remove binaries and object files
clean:
@echo "Cleaning up..."
rm -rvf *.o ${BINS}# Layout of a typical Makefile to compile any C program
# Source: https://opensource.com/article/18/8/what-how-makefile
# Usage:
# make # compile all binary
# make clean # remove ALL binaries and objects
.PHONY = all clean # define phony targets all and clean
CC = gcc # compiler to use
LINKERFLAG = -lm # define flags to be used with GCC in a recipe
SRCS := $(wildcard *.c) # function for filenames: stores all files with extension .c
BINS := $(SRCS:%.c=%) # substitution reference: output files have same names as source files, without .c extension
# phony target all calls values in${BINS} as individual targets
all: ${BINS}
# Equivalent to:
# foo: foo.o
# @echo "Checking.."
# gcc -lm foo.o -o foo
%: %.o
@echo "Checking.."
${CC} ${LINKERFLAG} $< -o $@
# Equivalent to:
# foo.o: foo.c
# @echo "Creating object.."
# gcc -c foo.c
%.o: %.c
@echo "Creating object.."
${CC} -c $<
# remove binaries and object files
clean:
@echo "Cleaning up..."
rm -rvf *.o ${BINS}# Rewritten, assuming only one file (foo.c) is used
.PHONY = all clean
CC = gcc
LINKERFLAG = -lm
SRCS := foo.c
BINS := foo
all: foo
foo: foo.o
@echo "Checking.."
gcc -lm foo.o -o foo
foo.o: foo.c
@echo "Creating object.."
gcc -c foo.c
clean:
@echo "Cleaning up..."
rm -rvf foo.o foo# Rewritten, assuming only one file (foo.c) is used
.PHONY = all clean
CC = gcc
LINKERFLAG = -lm
SRCS := foo.c
BINS := foo
all: foo
foo: foo.o
@echo "Checking.."
gcc -lm foo.o -o foo
foo.o: foo.c
@echo "Creating object.."
gcc -c foo.c
clean:
@echo "Cleaning up..."
rm -rvf foo.o fooSummary by Flavius Schmidt, ge83pux, 2023.
https://home.in.tum.de/~scfl