`make` not linking locally installed library automatically (CS50x's cs50.h) - makefile

I am trying to replicate CS50x's sandbox on my Gentoo system, but I am getting this kind of error when running make
% make price
cc price.c -o price
/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/cc9TASaL.o: in function `main':
price.c:(.text+0x15): undefined reference to `get_float'
collect2: error: ld returned 1 exit status
make: *** [<builtin>: price] Error 1
For reference, this is the source file:
% cat price.c
#include <stdio.h>
#include <cs50.h>
int main(void)
{
float price = get_float("What's the price?\n");
printf("Your total is %.2f (VAT included)\n", price * 1.22);
}
I have manually installed libcs50 on my system:
# ldconfig -p | grep cs50
libcs50.so.10 (libc6,x86-64) => /usr/local/lib64/libcs50.so.10
libcs50.so (libc6,x86-64) => /usr/local/lib64/libcs50.so
And when I compile the file with
% gcc -lcs50 price.c -o price
I am getting no errors.
Have I configured something wrong on my system, or have I misunderstood how make works?
After watching the lecture, I was under the impression that make would "automagically" add the -lcs50 parameter.
Thanks!
SOLUTION
Set CC, CFLAGS and LDLIBS according to these instructions: https://cs50.readthedocs.io/libraries/cs50/c/ .
All the "automagical" stuff in the lecture videos is possible thanks to those environment variables.

Make has a built-in rule that can build an executable from a single .c file:
%: %.c
# recipe to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $#
That way you don't have to write a Makefile for most simple tasks like this one.
You can find it using make -p | grep -C 3 '%: %.c\b'.
The built-in variable LINK.C evaluates to:
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
Seeing your last comment, all you have to do it call make while overriding the right variables:
make price CC=clang CFLAGS="-fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow" LDLIBS="-lcrypt -lcs50 -lm"

Related

Makefile cant find libraries

I'm trying to write my own makefile for a paho.mqtt project on a Raspberry Pi 4.
I've downloaded & tested the paho.mqtt install and its all working as expected.
So I'm now testing some C code but I just cant figure out the makefile (I'm new to this), my file so far,
NAME = mqtt_test
OBJ = $(NAME).o
LIBS = -libpaho-mqtt3c -libpaho-mqtt3cs
CFLAGS = -Wall -I/usr/local/include -L/usr/local/lib
CC = gcc
EXTENSION = .c
all: $(NAME)
%.o: %$(EXTENSION) $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$(NAME): $(OBJ)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
#rm -f *.o *~ core $(NAME)
This returns,
gcc -o mqtt_test mqtt_test.o -Wall -I/usr/local/include -L/usr/local/lib -libpaho-mqtt3c -libpaho-mqtt3cs
/usr/bin/ld: cannot find -libpaho-mqtt3c
/usr/bin/ld: cannot find -libpaho-mqtt3cs
collect2: error: ld returned 1 exit status
make: *** [makefile:14: mqtt_test] Error 1
I've checked & the includes and libraries are in the directories I put after the-I and -L flags.
When I look in /usr/bin there is no ld but there are paho files prefixed with paho_ but no library files.
What am I missing?
You don't use -libpaho-mqtt3c (etc.)
The option is -l so when you write -libpaho-mqtt3c the linker is looking for libraries named ibpaho-mqtt3c which of course do not exist: that would be either libibpaho-mqtt3c.a or libibpaho-mqtt3c.so.
You want to use -lpaho-mqtt3c: remove the lib at the front and the extension .a or .so, and add in the option -l.

script-file Not found by linker

when running a makefile, which includes a usage of
a script-file, I receive an error saying the linker doesn't find the script file.
When running the make file the output is as follows:
arm-none-eabi-gcc -g -Wall -Werror -c -o main.o main.c
arm-none-eabi-gcc -g -Wall -Werror -c -o misc.o misc.c
arm-none-eabi-gcc main.o misc.o misc.h -g -Wall -Werror -Wl,-Map=HOST.map -T=msp432p401r.lds -o HOST
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: cannot open linker script file =msp432p401r.lds: No such file or directory
collect2: error: ld returned 1 exit status
make: *** [Makefile:11: HOST] Error 1
The makefile content is:
#---- Variables (machine depending) --------
TARGET = HOST
CC = arm-none-eabi-gcc #gcc
CFLAGS = -g -Wall -Werror # compiler flags
LDFLAGS = -Wl,-Map=$(TARGET).map -T=msp432p401r.lds # linker flag
SOURCE = main.c misc.c misc.h
OBJS = $(SOURCE:.c=.o) # replace all c with o
#---- Targets -----------
$(TARGET): $(OBJS)
$(CC) $(OBJS) $(CFLAGS) $(LDFLAGS) -o $#
I have searched a lot for a solution for this issue, and tried various fixes, with no success.
The script file is located at the same location as the source files.
What can be the reason for not finding the file?
Thanks

Why recipe for target 'mykernel.bin' failed?

I'm trying to create a simple mykernel.bin file using Ubuntu.
GPPPARAM = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exception -fno-leading-underscore
ASPARAMS = --32
LDPARAMS = -m elf_i386
objects = loader.o kernel.o
%o: %.cpp
g++ $(GPPPARAM) -o $# -c $<
%o: %.s
as $(ASPARAMS) -o $# $<
mykernel.bin : linker.ld $(objects)
ld $(LDPARAMS) -T $< -o $# $(objects)
the output is:
make mykernel.bin
ld -m elf_i386 -T linker.ld -o mykernel.bin loader.o kernel.o
ld: i386:x86-64 architecture of input file loader.o' is incompatible with i386 output
ld: i386:x86-64 architecture of input filekernel.o' is incompatible with i386 output
Makefile:13: recipe for target 'mykernel.bin' failed
make: *** [mykernel.bin] Error 1
If you were to show the complete output, including the compile lines for your object files, then it would be clear that your compiler flags are not being used to compile your source code. As a result, the object files being generated are for your native operating system which is most likely 64bit, when you want 32bit.
The reason for this is as I described above: your pattern rule is wrong. You have written %o : %.cpp when you wanted to write %.o : %.cpp. The pattern rule you've written tells make that if it wants to build a file loader.o (so the stem of the pattern %o matches loader.) it can do so by compiling a file loader..cpp (because the pattern character % in %.cpp is replaced with the stem loader.). Since there's no loader..cpp file, your pattern is discarded as not matching and make proceeds to look for another pattern and it finds one, as a built-in rule.
But since you are using non-standard variable names GPPPARAM instead of the standard CXXFLAGS, none of your flags are used by the default rule.
You have two choices: you can either fix your pattern rules so they're correct:
%.o: %.cpp
g++ $(GPPPARAM) -o $# -c $<
%.o: %.s
as $(ASPARAMS) -o $# $<
Or you can get rid of your own pattern rules and use make's built-in rules, and set the standard variables to ensure your options are used:
CXX := g++
CXXFLAGS := -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exception -fno-leading-underscore
AS := as
ASFLAGS := --32

Some implicit makefile?

I am trying to understand makefile.
I took atmega168 bootloader's makefile and simplified it to this:
CC = avr-gcc
override CFLAGS = -g -Wall -Os -mmcu=atmega328p -DF_CPU=16000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600
atmega328: ATmegaBOOT_168_atmega328.hex
%.elf: ATmegaBOOT_168.o
avr-gcc -g -Wall -Os -mmcu=atmega328p -DF_CPU=16000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600 -Wl,--section-start=.text=0x7800 -o $# $<
clean:
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
%.hex: %.elf
avr-objcopy -j .text -j .data -O ihex $< $#
When I ran $ make atmega328 I get:
avr-gcc -g -Wall -Os -mmcu=atmega328p -DF_CPU=16000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600 -c -o ATmegaBOOT_168.o ATmegaBOOT_168.c
avr-gcc -g -Wall -Os -mmcu=atmega328p -DF_CPU=16000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600 -Wl,--section-start=.text=0x7800 -o ATmegaBOOT_168_atmega328.elf ATmegaBOOT_168.o
avr-objcopy -j .text -j .data -O ihex ATmegaBOOT_168_atmega328.elf ATmegaBOOT_168_atmega328.hex
rm ATmegaBOOT_168_atmega328.elf ATmegaBOOT_168.o
Why cannot I remove CC or CFLAGS?
I understand some basics of makefile. I read a lot on the internet, plus went through gnu manual, but I cannot understand the very first output with ATmegaBOOT_168.c. What/How has generated first command?
Was there used some second makefile? If yes, how to find its location?
UPDATE:
If I rename ATmegaBOOT_168.c to ATmegaBOOT_1681.c. Running $ make atmega328 gives:
make: *** No rule to make target 'ATmegaBOOT_168_atmega328.hex', needed by 'atmega328'. Stop.
but the rule is present.
CC and CFLAGS are variables used in the built in implicit rules of GNU make. When you run make, it reads your makefile a bit like:
No target given, so we'll make the first: atmega328. This requires a .hex file.
The .hex file can be generated from a .elf file per the last rule.
.elf files can be generated by the %.elf rule (which here looks like you've broken the pattern, as there's no % in the dependencies).
There's no rule for .o in this file, so the default recipe $(CC) $(CPPFLAGS) $(CFLAGS) -c is used. Since a .c file is found, this rule is applicable and generates the first command. The rule could have been written (as shown in suffix rules):
.c.o:
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $# $<
Backtrack up this list, now that the source has been found, and run the commands.
If the implicit rule variables are left unset, you will typically get programs built for your host system using cc.

Make target variable causes not input files

I am trying to use the following in a makefile, but when I type make filter_test it gives me the error below, and I can not figure out why. Note the spaces where the input files should be.
CXX=g++
CXXFLAGS=-O1 -pedantic -Wall -Werror -g
DEPS=p2.o recursive.o $#.cpp
p2.o: p2.cpp ; $(CXXFLAGS) -c p2.cpp
recursive.o: recursive.cpp ; $(CXXFLAGS) -c recursive.cpp
filter_test: p2.o $#.cpp recursive.o ; $(CXX) $(CXXFLAGS) recursive.o p2.o $#.cpp -o aaa
Output:
g++ -O1 -pedantic -Wall -Werror -g -o .cpp
g++: fatal error: no input files
compilation terminated.
make: *** [.cpp] Error 4
$# only has a value inside the recipe, so when make sees $# in the prerequisite list, it treats it as an empty string. So make is trying to build the pre-requisite .cpp and using the default rule to build it. To fix this just write:
filter_test: p2.o filter_test.cpp recursive.o
Leave the recipe blank and let make use default rules.

Resources