Makefile:30: recipe for target 'obj/main.o' failed - c

I'm trying to use the makefile on windows, it seems not to be very common to use Makefile on Windows, so I followed some steps installing MingW, which is used for compilation, but when running make, this error occurred:
mkdir -p ./obj/
The command syntax is incorrect.
Makefile:30: recipe for target 'obj/main.o' failed
mingw32-make.exe: *** [obj/main.o] Error 1
Here's the code:
NAME = minishell
LIBFT = libft.a
CC = cc
CF = -g -Wall -Wextra -Werror
CFI = -I $(INCLUDE)
CREADLINE = -lreadline
LIBFT_PATH = ./libs/libft/
SRC_PATH = ./sources/
OBJ_PATH = ./obj/
INCLUDE = ./includes/
SRC = main.c\
prompt.c\
exec.c pipe.c paths.c command.c\
utils_pipes.c\
signals.c\
VPATH := $(SRC_PATH)\
$(SRC_PATH)prompt\
$(SRC_PATH)execute\
$(SRC_PATH)utils\
OBJ = $(addprefix $(OBJ_PATH), $(notdir $(SRC:.c=.o)))
RM = rm -rf
$(OBJ_PATH)%.o: %.c
mkdir -p $(OBJ_PATH)
$(CC) $(CF) $(CFI) -c $< -o $#
$(NAME): $(OBJ)
make -C $(LIBFT_PATH) $(LIBFT)
$(CC) -g $(CF) -I $(INCLUDE) -o $(NAME) $(OBJ) -L $(LIBFT_PATH) -lft $(CREADLINE)
#echo "$(GREEN)$(NAME) created$(DEFAULT)"
all: $(NAME)
re: fclean all
clean:
make -C $(LIBFT_PATH) clean
$(RM) $(OBJ) $(OBJDIR)
#echo "$(YELLOW)object files deleted$(DEFAULT)"
fclean: clean
make -C $(LIBFT_PATH) fclean
$(RM) $(NAME)
#echo "$(RED)all deleted$(DEFAULT)"
install:
sudo apt-get install -y libreadline-dev valgrind
leak:
valgrind --suppressions=readline.supp --leak-check=full --track-origins=yes --show-leak-kinds=all ./$(NAME)
.PHONY: all clean fclean re bonus rebonus
#COLORS
RED = \033[1;31m
GREEN = \033[1;32m
YELLOW = \033[1;33m
DEFAULT = \033[0m`
Could anyone give an idea how to fix this?

A makefile contains two different types of text. There is makefile syntax, which is parsed by make. This is all the text in the makefile which is not indented with a TAB character. The syntax for this is described in the make documentation.
Then there is shell script syntax, which is not parsed by make. This is all the text that is indented by a TAB character. This text is not handled by make; instead make invokes a shell program to run these commands.
On a POSIX-based system such as GNU/Linux, MacOS, the *BSD systems, etc., they all use the same basic shell and set of utilities as defined by the POSIX standard. mkdir -p is a POSIX command plus option, directories are separated by forward-slash, and everything works nicely.
The make utility was created in the 1970's on a UNIX (POSIX-base) system and appears on every POSIX systems since.
On Windows, the world is very different. The tools (like mkdir) work differently on Windows, the paths are constructed differently ("drive letters", backslashes for separators, etc.), there are multiple shells (cmd.exe and PowerShell) and none of these shells work the same way as the POSIX standard.
All this to say, it's very tricky to write a single makefile that will work on both POSIX and Windows environments because they are very very different.
Your options are (a) install a POSIX environment on you Windows system and run make from there using all POSIX tools, or (b) use make variables to hold different commands based on the OS type you're using, so that your rules can be portable.
In your makefile, it is invoking the Windows cmd.exe shell, which is trying to run the Windows mkdir program, which does not understand the POSIX -p option. So you get this error.

First: Make expects as first character of a command a real tab ('\t'), not blanks (' ').
Enable your editor to show you white space character and check this.
You can put blanks or more tabs after the initial tab, if you need to.
Anyway, this seems not to be the core issue.
Your Makefile is using command lines for another shell than CMD. You need to adjust them to the other syntax.
For example, unixoid operating systems know the command "mkdir", which allows the option "-p" to create all directories on the way to the final one, if they do not exist. This is for safety reasons. CMD's version of "mkdir" does not know this option, beside the fact that it does not accept forward-slashes as path separators.

Related

How to compile and run a infinite loop .c program in a Makefile

System: VirtualBox Ubuntu 20.04
This question sounds like stupid, but I have stuck at this problem for hours. (Purely new to Makefile)
Here is the description:
The program (sh.c)simulates a shell, which is a infinite loop. User can exit if they enter builtin command exit, like below:
> gcc -o sh sh.c
> ./sh
>>> $ (user can enter command)
...
...
>>> $ exit
Goodbye!
> (back to bash)
The question is if I want to place gcc -o sh sh.c and ./sh into Makefile and enter make to run, bash will stuck like this:
> make
gcc sh.c -o sh
./sh
(stucking...)
and I cannot type commands also cannot exit by Ctrl + C.
I believe the problem is in the Makefile, because program can run smoothly if I don't use Makefile, and below is my Makefile:
all: compile run
.PHONY: all clean
CC := gcc
FLAG := -Wall
SRC := sh.c
EXE := sh
compile: $(SRC)
$(CC) -o $(EXE) $(SRC)
run:
./$(EXE)
clean:
rm -rf $(EXE)
I wonder what is the problem in the Makefile, thanks in advance!
The reason for this weird behavior must be related to your implementation of sh.c. Using a normal shell, for example, works fine for me:
$ cat Makefile
run: ; /bin/sh
Now I can run make and it starts a shell and I can type stuff into it and it works:
$ make
/bin/sh
$ echo hi
hi
$ exit
But, as John says, make is not intended to allow you to run interactive programs. It's intended to allow you to build programs and run other commands non-interactively. If you use make -j for example (parallel builds) only one rule can get access to stdin at a time and there's no way to know which one it will be. Etc.
You should keep the compile rule (although it should be written differently: it's always wrong for a make recipe to build a different file than the name of the target) but throw away the run rule, and just run the command from your shell prompt after make is done.
all: $(EXE)
$(EXE): $(SRC)
$(CC) -o $(EXE) $(SRC)

Using rm -i !(*.c|Makefile) in Makefile?

I have a directory where I have some C program files and a Makefile with executables of those C files. I can simply run this to remove all the executable at once in rm !(*.c|Makefile).
But when i am adding this to my makefile
CFLAGS= -Wall -g -lm
SHELL=/bin/bash
careful:
echo "nothing"
clean:
rm -i !(*.c|Makefile)
I am getting this error while executing the command
/bin/bash: -c: line 1: syntax error near unexpected token `('
/bin/bash: -c: line 1: `rm -i !(*.c|Makefile)'
make: *** [Makefile:8: clean] Error 2
I am not too knowledgeable about Bash syntax but I know that () is treated as a subshell, I think that's why I can't run rm (*.c) directly in the terminal because *.c is not a command (or any valid syntax). But running rm -i !(*.c) works in the terminal. So I guess !() is treated differently in Bash.
My assumption on all this: in Makefile when I am running make clean it is treating !(*.c|Makefile), differently than in normal terminal, or somehow it is disregarding ! in !(*.c|Makefile)
So my questions are:
Are !() and () treated differently in Bash?
Why does !(wildcard) work in the terminal but not in my Makefile
How can I make it work in the Makefile?
The Bash-specific extended globbing patterns are not enabled out of the box for noninteractive shells.
!(...) is purely part of this wildcard syntax, and has nothing with subshells to do.
Probably a better solution anyway is to refactor this so you don't depend on Bash.
.PHONY: clean
clean:
rm -i $(filter-out $(wildcard *.c) Makefile,$(wildcard *))
The Bash Reference Manual doesn't have a good anchor to link to, but the extended globbing syntax available with extglob is described in the section on Pattern Matching
If you really wanted to, you could shopt -s extglob in your Makefile, too, but this gets rather complicated as you will have to hide the statement from the parser until the shell is configured to understand this syntax. For example,
.PHONY: clean
clean:
shopt -s extglob; \
eval 'rm -i !(*.c|Makefile)'
Notice also how shopt and eval need to be on the same logical line, as make out of the box executes each recipe line in a separate new shell instance (though you can change that with .ONESHELL)

Makefile not generating debugging information with -g flag

I recently moved from working in the terminal to VScode and am needing to generate debugging information to use with the debugger in vscode.
My makefile is:
SRCS = src/ft_argcheck.c \
src/ft_operations.c \
src/ft_stcutils.c \
src/push_swap.c
NAME = push_swap
INCS = inc/push_swap.h
OBJS = $(SRCS:c=o)
CC = gcc
CFLAGS = -g -Wall -Wextra -Werror
RM = rm -f
LIBFT = libft/libft.a
LIBFT_DIR = libft
.PHONY: all bonus clean fclean re
all: $(NAME)
$(NAME): $(OBJS)
#make -C $(LIBFT_DIR) --silent
#$(CC) $(CFLAGS) -I$(INCS) -o $(NAME) $(OBJS) -L $(LIBFT_DIR) -lft
clean:
#$(RM) $(OBJS)
#make -s clean -C $(LIBFT_DIR)
fclean: clean
#$(RM) $(NAME)
#make -s fclean -C $(LIBFT_DIR)
re: fclean all
But despite adding the -g flag, no debugging information is generated. on which I can run lldb.
A good proposal is to remove the #s in front of the command names to see what commands make is executing.... To make a program debuggable, you need to check that all the compilation steps are done using the -g flag and that the linking step has also included the -g flag. Also a good option is to specify no optimization so you will not get to problems with breakpoints you cannot fix because the compiler has eliminated or changed the final code, and has broken the correspondence between source lines and points in the code.
If you take off all the #s there, you will see the commands as make is executing them, think you don't see now. I think there's a command (berkeley make has it) to make make to print the commands even though the #s remain in place.
By the way, as you are telling you are using vscode it should be fine if you execute make on the command line alone, to see the output of the commands, and try to see if it is some problem with make or with vscode itself.
As you have not provided your complete project, I'm sorry to say that I can only test it with dumb/fake files and no program can be made to test it with gdb.
I guess that the problem is that you have put your project sources in a different directory than where the program is built, and the sources cannot be found by gdb and so, no source debugging can be done because gdb cannot find the source files. Gdb has some way to specify the path to the source files... You should look at gdb documentation.
Thanks for all your answers (Removing # didn't really give me much more information, as it did show the -g flag and I already tried remaking everything with fclean). I seem to have figured out an easy fix with the help of a friend:
add a rule "debug"
debug:
$(CC) -g $(CFLAGS) -I$(INCS) $(LIBFT) $(SRCS) -o $(NAME)
which we can run just when we want to generate the debugging information and run this directly with $(SRCS) instead of running it on the $(OBJS) as in the normal command.

What is Eclipse CDT is doing with 'make' under the hood

I'm on Windows 7 and have MinGW/gcc installed. I'm using the Eclipse CDT plugin to compile and build my first simple C programs, and am trying to follow what exactly the plugin is doing under the hood.
I create a new "Hello World!" C project with the following directory structure:
helloworld/
src/
helloworld.c
Where helloworld.c is:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
puts("Hello World!");
return EXIT_SUCCESS;
}
So I created a Run Configuration in Debug Mode (as opposed to "Release Mode", not a "Debug Configuration" in typical Eclipse parlance!) and ran my app, and it works beautifully, printing "Hello World!" to the Eclipse console.
Now I'm looking on my file system and the file/project structure is like so:
helloworld/
src/
helloworld.c
Debug/
src/
helloworld.d
helloworld.o
subdir.mk
helloworld.exe
makefile
objects.mk
source.mk
I assume that running my Run Configuration in Eclipse (hence compiling/building/running helloworld inside Eclipse) created everything under Debug. Furthermore I assume that helloworld.d and helloworld.o are compiled binaries, and that helloworld.exe is the packaged executable containing those binaries and everything they'red linked to (stdio and stdlib). I also assume makefile is the actual Make file (buildscript), and that the *.mk files are somehow inputs to that buildscript. So, for starters, if any of those assumptions are wrong, please begin by correcting me!
When I open makefile I see this:
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
-include ../makefile.init
RM := rm -rf
# All of the sources participating in the build are defined here
-include sources.mk
-include src/subdir.mk
-include subdir.mk
-include objects.mk
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
endif
-include ../makefile.defs
# Add inputs and outputs from these tool invocations to the build variables
# All Target
all: helloworld
# Tool invocations
helloworld: $(OBJS) $(USER_OBJS)
#echo 'Building target: $#'
#echo 'Invoking: Cross GCC Linker'
gcc -o "helloworld" $(OBJS) $(USER_OBJS) $(LIBS)
#echo 'Finished building target: $#'
#echo ' '
# Other Targets
clean:
-$(RM) $(EXECUTABLES)$(OBJS)$(C_DEPS) helloworld
-#echo ' '
.PHONY: all clean dependents
.SECONDARY:
-include ../makefile.targets
Please note: I am not looking for someone to explain to me how Make works, I can RTFM for that ;-)
I am just trying to understand what it would take to compile, build and run helloworld from the command-line, outside of Eclipse. What command line invocations would I need to accomplish this, and why? Once I see that, combined with perusing Make docs, I should be able to fill in the gaps and understand everything that is going on.
That depends a bit on the paths that Eclipse generates in the files source.mk and objects.mk but most likely you need to cd into the Debug folder.
Inside of that, you can then run make all to compile the project.
If Eclipse generated absolute paths, you can use make -f .../path/to/helloworld/Debug/makefile all from anywhere.
The *.o files are the object file(s) created by compilation. these files are typically build by a command like:
Gcc -ansi -Wall -pedantic -c helloworld.c -o helloworld.o
(apologies foe capitalization of gcc, my iPad insists on correct my typing)
The *.exe is the actual executable, which may or may not contain the library functions. This depends on static versus dynamic linking. The executable is created typically by:
Gcc helloworld.o -o helloworld.exe
The *.d files are dependency files, built by gcc attempting to determine dependencies between files, typically built with the following command
MAKEDEPEND = gcc -M $(CPPFLAGS) -o $*.d $<
(Rule taken from make online documentation).
So,to answer your final question, to compile from the command line, a command like:
Foo gcc -ansi -WAll -pedantic helloworld.c -o helloworld.exe
Should do the trick for you. Note, the flags to the compiler are the minimum that I like to use, you will probably have a different set of switches.
Hopes this help,
T

How to properly make my makefile to compile and run?

The question is probably not the best one to describe my issue but I couldn't think of a better one. My makefile goes like this:
PROGRAM_NAME = prog
OBJECT_FILES = $(PROGRAM_NAME).o
CFLAGS = -O2 -Wall -g
$(PROGRAM_NAME) : $(OBJECT_FILES)
gcc $(CFLAGS) -o $# $(OBJECT_FILES)
$(PROGRAM_NAME).o : $(PROGRAM_NAME).c data.h
gcc $(CFLAGS) -c $<
clean :
$(RM) $(PROGRAM_NAME)
$(RM) $(OBJECT_FILES)
$(RM) *~ *.bak
run :
#$(MAKE) && ./$(PROGRAM_NAME) $(ARGS)
When I want to compile and run I just do "make run". The issue with this is that my program handles the signal produced by Ctrl+Z and if I start my program with "make run", the signal will be sent to "make run" and not my program itself.
Basically, calling "make run" is not the same thing as calling directly "make && ./prog" because in the first case, "make run" will not terminate unless "prog" terminates first.
Is there a way around this?
You can simplify your 'run' target by having it depend on whether your program is up to date, and then simply run the program:
run: ${PROGRAM_NAME}
./${PROGRAM} ${ARGS}
There's not much point in running make when you're already running make - at least, not in this context. Maybe for recursive operations (in different directories), but see 'Recursive Make Considered Harmful'.
Also, your makefile should normally provide a target 'all' and it should normally the first and therefore default target.
Running from the makefile is a bit unusual. Are you, perhaps, trying to duplicate the "Compile and Run" Menu item that some IDE provide? Make is not well equipped to do that.
All the stuff that happens in the target commands happens in sub-processes that are not attached directly to the terminal, which is why make receives your key stroke.
Another thing to look at: usually the object-file to executable stage (linking) uses a different set of flags (LDFLAGS and LIBS) then the compile stage. In this simple example you can get away with it, but if you copy this makefile for use in a more complicated case you'll run into trouble.
If you're going to build and run over and over, You can use the history command to help with this:
# Run this once
make && ./foo
# Repeat last command
!!
As dmckee's answer said, make(1) is making something, not for compile-and-run.
Of course, nothing stops you for creating a shell alias make-run which does the intended 'make && ./prog args'.
You can try like this:
APP = olupxtest
SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o)
CXXFLAGS = -g -fPIC -c
LDFLAGS =
LIBS =
.PHONY: all clean
all: clean $(APP) run
$(APP): $(OBJS)
$(CXX) $(LDFLAGS) $^ $(LIBS) -o $#
clean:
$(RM) $(OBJS) $(APP)
run: ${APP}
./${APP} ${ARGS}
Here you have calling multiple rules for target: all: clean $(APP) run

Resources