Makefile does not detect files inside folders - makefile

I've serious problems trying to compile this makefile inside a AIX environment.
The folder structure is as follows (using the command provided in one of the answers here: Linux command to print directory structure in the form of a tree find . | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/" ):
|-src
| |-main.c
|-obj
|-bin
|-Makefile
|-main.c
I'm trying to compile this structure using this makefile:
.SUFFIXES:
.DEFAULT:
CC = xlc_r
CFLAGSD = -g
CFLAGS = -Wall
CDEF =
LOADOPTS =
BIN_DIR = bin/
OBJ_DIR = obj/
SRC_DIR = src/
LIB_DIR = lib/
INC_DIR = include/
INC_BASE = -I./$(INC_DIR)
INC_SOURCE = -I./$(SRC_DIR)
INC_ALL = $(INC_BASE) $(INC_SOURCE)
# Libraries packed in macros
LIB_BASE = -L./$(LIB_DIR)
LIB_MATH = -lm
LIB_ALL = -lrt $(LIB_BASE)
# Libraries needed by the different programs and their respective names
LIB_PROGRAM_01 = $(LIB_ALL)
PROGRAM_NAME_01 = main
.PHONY: all
all: $(PROGRAM_NAME_01) \
execute \
$(OBJ_DIR)%.o: $(SRC_DIR)%.c
# --- Compiling $< ---
# $(CC) $(CFLAGSD) $(INC_ALL) -c $(SRC_DIR)$< -o $(OBJ_DIR)$#
create_directories:
if [ ! -d ./$(BIN_DIR) ]; then mkdir -p ./$(BIN_DIR);fi
if [ ! -d ./$(OBJ_DIR) ]; then mkdir -p ./$(OBJ_DIR);fi
execute: $(PROGRAM_NAME_01)
# --- Execute $< ---
# ./$(BIN_DIR)$<
$(PROGRAM_NAME_01): $(OBJ_DIR)main.o
# --- Linking $< ---
# $(CC) $(CDEF) $^ -o $(BIN_DIR)$# $(INC_ALL) $(LIB_PROGRAM_01)
cleanobj:
# --- Clean all objects ---
# rm -f $(OBJ_DIR)*.o
clean:
# --- Clean all objects and the bin dir too ---
# rm -f $(OBJ_DIR)*.o $(BIN_DIR)*
allc: all \
cleanobj
Debug: all
Release: all
default: all
The error I obtain is the next:
make: 1254-002 Cannot find a rule to create target obj/main.o from dependencies.
But, if I try to compile in Cygwin or Debian, it works.
I tried to call make -r -d to see all the internals and debugging simbols, but it never refers to anything close remotely to the src/main.c file.
With -d, the makefile shows the follows:
#
# Files that are only sources:
# src/%.c [src/%.c]
# obj/main.o [obj/main.o]
#*** Internal (default) Variables:
#*** Global Variables:
The version of make in aix is: 1.1.1.3 using the command grep bos /usr/ccs/lib/aix.mk

Your makefile is a GNU Make makefile but your AIX make program is not GNU Make
and will not understand many GNU Make makefiles. Your make program in Cygwin or Debian is GNU Make.
Install and use GNU Make.

Related

Wildcard Pattern Matching in Make

Here is my project structure.
| - src
| - boot
| - table.s
| - boot.s
| - machine
| - revb
| - memmap
| - vars.s
| - os
| - utils
| - ...lots here
I am grouping features by folder, and have a special folder for machine specific code, link scripts, anything.
The problem I am having with make is that I can't seem to get the Pattern match to work.
The below runs and builds the .o files.
#This gets repetative as every file needs to have a recipe by itself.
$(TARGET_DIR)/hash.o : $(SRC_DIR)/utils/hash.s machine
#echo "compiling $<"
$(CC) $(CFLAGS) $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
The below does NOT work. It doesn't run any of the commands.
#if this works that would be perfect every folder/file will be a recipe!
$(TARGET_DIR)/%.o : $(SRC_DIR)/%.s machine
#echo "compiling $<"
$(CC) $(CFLAGS) $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
Nothing runs at all, For some reason no files seem to match that pattern.
I have also tried this.
# if this works, it would be a bit annoying as this is per feature recipe/target.
$(TARGET_DIR)/%.o : $(SRC_DIR)/boot/%.s machine
#echo "compiling $<"
$(CC) $(CFLAGS) $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
Edit
full makefile for reference
CFLAGS = -march=rv32i -mabi=ilp32
CC = riscv32-unknown-linux-gnu-as
LINKER = riscv32-unknown-linux-gnu-ld
DUMP = riscv32-unknown-linux-gnu-objdump
COPY = riscv32-unknown-linux-gnu-objcopy
SRC_DIR = src
TARGET_DIR = target
MACHINE_FILES_DIR = machine
TARGET_MACHINE = revb
# vizoros : $(TARGET_DIR)/%.o
# $(LINKER) $(TARGET_DIR)/boot.o $(TARGET_DIR)/table.o $(TARGET_DIR)/os.o $(TARGET_DIR)/hash.o -T $(TARGET_DIR)/memmap -o $(TARGET_DIR)/$#.elf
# $(DUMP) -D $(TARGET_DIR)/$#.elf > $(TARGET_DIR)/$#.list
$(TARGET_DIR)/%.o : $(SRC_DIR)/boot/%.s machine
#echo "compiling $<"
$(CC) $(CFLAGS) $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
machine: folders
cp -r $(SRC_DIR)/$(MACHINE_FILES_DIR)/$(TARGET_MACHINE)/. $(TARGET_DIR)
folders:
mkdir -p $(TARGET_DIR)
.phony: clean
clean:
rm -rf $(TARGET_DIR)
As with your other question, you are expecting too much fancy capability from make. Make is a very simple tool. It will not go looking around your directories for files that could be built. It will build only exactly what you ask it to build. It will not infer matching files based on heuristics: it will match only exact strings.
Make always works backwards: it starts with the final target you ask it to build and finds a rule that can build that. Then it looks at each of the prerequisites of that final target and finds a rule that can build each one of those. Then it looks at any prerequisites of each of the prerequisites of those, etc. Once it has built (or found source files for) all the prerequisites of a target, it builds that target, then walks back up until finally it builds the final target you asked for.
In your makefile above you've commented out the "final target" you want built (vizoros), so of course make will not build it.
I'm just going to give you a makefile that solves your problem... if you want to understand what it does please consult the GNU make manual. Note I haven't actually tried this, I just wrote it here. Also note I omitted the whole machine thing because I don't understand what it's supposed to do and you didn't really define it.
CFLAGS = -march=rv32i -mabi=ilp32
CC = riscv32-unknown-linux-gnu-as
LINKER = riscv32-unknown-linux-gnu-ld
DUMP = riscv32-unknown-linux-gnu-objdump
COPY = riscv32-unknown-linux-gnu-objcopy
SRC_DIR = src
TARGET_DIR = target
MACHINE_FILES_DIR = machine
TARGET_MACHINE = revb
# Find all .s files under SRC_DIR
SRCS := $(shell find $(SRC_DIR) -name \*.s)
# Use VPATH with a list of directories to be searched for
VPATH := $(sort $(dir $(SRCS)))
# Convert all .s files into .o files directly under TARGET_DIR
# First strip off the directory, then convert
OBJS := $(patsubst %.s,$(TARGET_DIR)/%.o,$(notdir $(SRCS)))
# Define the final target and provide all the object files as prerequisites
$(TARGET_DIR)/vizoros.elf : $(OBJS)
mkdir -p $(#D)
$(LINKER) $^ -T $(TARGET_DIR)/memmap -o $#
$(DUMP) -D $# > $(#:.elf=.list)
# Define a pattern rule to build an object file in TARGET_DIR
# The source file will be searched for via VPATH
$(TARGET_DIR)/%.o : %.s
mkdir -p $(#D)
#echo "compiling $<"
$(CC) $(CFLAGS) -c $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
# It must be .PHONY, not .phony: make, like all POSIX tools, is
# case-sensitive
.PHONY: clean
clean:
rm -rf $(TARGET_DIR)
References:
GNU make manual
= vs := variables
shell function
dir and notdir functions
sort and patsubst functions
VPATH
Substitution references
Automatic variables
Phony targets
Also note you had an error in your compile command; you were missing the -c option which tells the compiler to generate an object file rather than a final executable file.

g++ compiler error - g++: error: spawn: No such file or Directory

I am trying to compile a .ttcn file with my a generated makefile with role is to create a .cc and .hh file.
But when I run the make command I have a problem with the .o file, it is not generated so my .exe is not generated too
here is the error I have and my Makefile:
Makefile:
# This Makefile was generated by the Makefile Generator
# of the TTCN-3 Test Executor version CRL 113 200/5 R2A
# for U-TMV\qi11091 (qi11091#WMUC-0118) on Thu Apr 9 16:49:49 2015
# Copyright Ericsson Telecom AB 2000-2014
# The following make commands are available:
# - make, make all Builds the executable test suite.
# - make archive Archives all source files.
# - make check Checks the semantics of TTCN-3 and ASN.1 modules.
# - make clean Removes all generated files.
# - make compile Translates TTCN-3 and ASN.1 modules to C++.
# - make dep Creates/updates dependency list.
# - make executable Builds the executable test suite.
# - make library Builds the library archive.
# - make objects Builds the object files without linking the executable.
# WARNING! This Makefile can be used with GNU make only.
# Other versions of make may report syntax errors in it.
#
# Do NOT touch this line...
#
.PHONY: all shared_objects executable library objects check clean dep archive
.SUFFIXES: .d
#
# Set these variables...
#
# The path of your TTCN-3 Test Executor installation:
# Uncomment this line to override the environment variable.
# TTCN3_DIR =
# Your platform: (SOLARIS, SOLARIS8, LINUX, FREEBSD or WIN32)
PLATFORM = WIN32
# Your C++ compiler:
# (if you change the platform, you may need to change the compiler)
CXX = g++
# Flags for the C++ preprocessor (and makedepend as well):
CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)/include
# Flags for dependency generation
CXXDEPFLAGS = -MM
# Flags for the C++ compiler:
CXXFLAGS = -Wall
# Flags for the linker:
LDFLAGS =
ifeq ($(PLATFORM), WIN32)
# Silence linker warnings.
LDFLAGS += -Wl,--enable-auto-import,--enable-runtime-pseudo-reloc
endif
# Utility to create library files
AR = ar
ARFLAGS =
# Flags for the TTCN-3 and ASN.1 compiler:
COMPILER_FLAGS = -L
# Execution mode: (either ttcn3 or ttcn3-parallel)
TTCN3_LIB = ttcn3-parallel
# The path of your libxml2 installation:
# If you do not have your own one, leave it unchanged.
XMLDIR = $(TTCN3_DIR)
# Directory to store the archived source files:
ARCHIVE_DIR = backup
#
# You may change these variables. Add your files if necessary...
#
# TTCN-3 modules of this project:
TTCN3_MODULES = TTCN3SessionSetup.ttcn
# ASN.1 modules of this project:
ASN1_MODULES =
# C++ source & header files generated from the TTCN-3 & ASN.1 modules of
# this project:
GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) $(ASN1_MODULES:.asn=.cc)
GENERATED_HEADERS = $(GENERATED_SOURCES:.cc=.hh)
# C/C++ Source & header files of Test Ports, external functions and
# other modules:
USER_SOURCES =
USER_HEADERS = $(USER_SOURCES:.cc=.hh)
# Object files of this project that are needed for the executable test suite:
OBJECTS = $(GENERATED_OBJECTS) $(USER_OBJECTS)
GENERATED_OBJECTS = $(GENERATED_SOURCES:.cc=.o)
USER_OBJECTS = $(USER_SOURCES:.cc=.o)
DEPFILES = $(USER_OBJECTS:.o=.d) $(GENERATED_OBJECTS:.o=.d)
# Other files of the project (Makefile, configuration files, etc.)
# that will be added to the archived source files:
OTHER_FILES = Makefile
# The name of the executable test suite:
EXECUTABLE = TTCN3SessionSetup.exe
LIBRARY = libTTCN3SessionSetup.a
TARGET = $(EXECUTABLE)
#
# Do not modify these unless you know what you are doing...
# Platform specific additional libraries:
#
SOLARIS_LIBS = -lsocket -lnsl -lxml2
SOLARIS8_LIBS = -lsocket -lnsl -lxml2
LINUX_LIBS = -lxml2
FREEBSD_LIBS = -lxml2
WIN32_LIBS = -lxml2
#
# Rules for building the executable...
#
all: $(TARGET) ;
executable: $(EXECUTABLE) ;
library: $(LIBRARY) ;
objects: $(OBJECTS) compile;
$(EXECUTABLE): $(OBJECTS)
if $(CXX) $(LDFLAGS) -o $# $^ \
-L$(TTCN3_DIR)/lib -l$(TTCN3_LIB) \
-L$(OPENSSL_DIR)/lib -lcrypto \
-L$(XMLDIR)/lib $($(PLATFORM)_LIBS); \
then : ; else $(TTCN3_DIR)/bin/titanver $(OBJECTS); exit 1; fi
$(LIBRARY): $(OBJECTS)
$(AR) -r $(ARFLAGS) $(LIBRARY) $(OBJECTS)
.cc.o .c.o:
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $# $<
.cc.d .c.d:
#echo Creating dependency file for '$<'; set -e; \
$(CXX) $(CXXDEPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $< \
| sed 's/\($*\)\.o[ :]*/\1.o $# : /g' > $#; \
[ -s $# ] || rm -f $#
$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile
#if [ ! -f $# ]; then $(RM) compile; $(MAKE) compile; fi
check: $(TTCN3_MODULES) $(ASN1_MODULES)
$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) $^
compile: $(TTCN3_MODULES) $(ASN1_MODULES)
$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) $^ - $?
touch $#
clean:
-$(RM) $(EXECUTABLE) $(LIBRARY) $(OBJECTS) $(GENERATED_HEADERS) \
$(GENERATED_SOURCES) compile $(DEPFILES) \
tags *.log
dep: $(GENERATED_SOURCES) $(USER_SOURCES) ;
ifeq ($(findstring n,$(MAKEFLAGS)),)
ifeq ($(filter clean check compile archive diag,$(MAKECMDGOALS)),)
-include $(DEPFILES)
endif
endif
archive:
mkdir -p $(ARCHIVE_DIR)
tar -cvhf - $(TTCN3_MODULES) $(ASN1_MODULES) \
$(USER_HEADERS) $(USER_SOURCES) $(OTHER_FILES) \
| gzip >$(ARCHIVE_DIR)/`basename $(TARGET) .exe`-`date '+%y%m%d-%H%M'`.tgz
diag:
$(TTCN3_DIR)/bin/compiler -v 2>&1
$(TTCN3_DIR)/bin/mctr_cli -v 2>&1
$(CXX) -v 2>&1
$(AR) -V 2>&1
#echo TTCN3_DIR=$(TTCN3_DIR)
#echo OPENSSL_DIR=$(OPENSSL_DIR)
#echo XMLDIR=$(XMLDIR)
#echo PLATFORM=$(PLATFORM)
#
# Add your rules here if necessary...
#
And here is my error
qi11091#WMUC-0118 ~/Documents/TITAN_Command_Line/FirstTest
$ make
/cygdrive/c/Users/qi11091/Documents/TITAN_files/TITAN/bin/compiler -L TTCN3Ses sionSetup.ttcn - TTCN3SessionSetup.ttcn
Notify: Parsing TTCN-3 module `TTCN3SessionSetup.ttcn'...
Notify: Checking modules...
Notify: Generating code...
Notify: File `TTCN3SessionSetup.hh' was generated.
Notify: File `TTCN3SessionSetup.cc' was generated.
Notify: 2 files were updated.
touch compile
Creating dependency file for TTCN3SessionSetup.cc
g++: Fehler: spawn: No such file or directory
g++ -c -DWIN32 -I/cygdrive/c/Users/qi11091/Documents/TITAN_files/TITAN /include -Wall -o TTCN3SessionSetup.o TTCN3SessionSetup.cc
g++: Fehler: spawn: No such file or directory
Makefile:151: die Regel für Ziel „TTCN3SessionSetup.o“ scheiterte
make: *** [TTCN3SessionSetup.o] Fehler 1
If that's an exact copy of the output you're seeing, then one problem is:
g++ -c -DWIN32 -I/cygdrive/c/Users/qi11091/Documents/TITAN_files/TITAN /include -Wall -o TTCN3SessionSetup.o TTCN3SessionSetup.cc
Note all the spaces between .../TITAN_files/TITAN and /include. That whitespace makes the compiler think these are separate arguments, and it seems like you're trying to add the "file" /include to your compile line, which does not exist of course.
Your makefile doesn't actually set the TTCN3_DIR variable, in this example, so I don't know where that value is coming from but wherever it is, you need to be sure there is no whitespace at the end of the value.

makefile pathing issues on OSX

OK, I thought I would try one last update and see if it gets me anywhere. I've created a very small test case. This should not build anything, it just tests the path settings. Also I've setup the path so there are no spaces. The is the smallest, simplest test case I could come up with.
This makefile will set the path, echo the path, run avr-gcc -v with the full path specified and then try to run it without the full path specified. It should find avr-gcc in the path on the second try, but does not.
makefile
TOOLCHAIN := /Users/justinzaun/Desktop/AVRBuilder.app/Contents/Resources/avrchain
PATH := ${TOOLCHAIN}/bin:${PATH}
export PATH
all:
#echo ${PATH}
#echo --------
"${TOOLCHAIN}/bin/avr-gcc" -v
#echo --------
avr-gcc -v
output
JUSTINs-MacBook-Air:Untitled justinzaun$ make
/Users/justinzaun/Desktop/AVRBuilder.app/Contents/Resources/avrchain/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
--------
"/Users/justinzaun/Desktop/AVRBuilder.app/Contents/Resources/avrchain/bin/avr-gcc" -v
Using built-in specs.
COLLECT_GCC=/Users/justinzaun/Desktop/AVRBuilder.app/Contents/Resources/avrchain/bin/avr-gcc
COLLECT_LTO_WRAPPER=/Users/justinzaun/Desktop/AVRBuilder.app/Contents/Resources/avrchain/bin/../libexec/gcc/avr/4.6.3/lto-wrapper
Target: avr
Configured with: /Users/justinzaun/Development/AVRBuilder/Packages/gccobj/../gcc/configure --prefix=/Users/justinzaun/Development/AVRBuilder/Packages/gccobj/../build/ --exec-prefix=/Users/justinzaun/Development/AVRBuilder/Packages/gccobj/../build/ --datadir=/Users/justinzaun/Development/AVRBuilder/Packages/gccobj/../build/ --target=avr --enable-languages=c,objc,c++ --disable-libssp --disable-lto --disable-nls --disable-libgomp --disable-gdbtk --disable-threads --enable-poison-system-directories
Thread model: single
gcc version 4.6.3 (GCC)
--------
avr-gcc -v
make: avr-gcc: No such file or directory
make: *** [all] Error 1
JUSTINs-MacBook-Air:Untitled justinzaun$
Original Question
I'm trying to set the path from within the makefile. I can't seem to do this on OSX. Setting the path with PATH := /new/bin/:$(PATH) does not work. See my makefile below.
makefile
PROJECTNAME = Untitled
# Name of target controller
# (e.g. 'at90s8515', see the available avr-gcc mmcu
# options for possible values)
MCU = atmega640
# id to use with programmer
# default: PROGRAMMER_MCU=$(MCU)
# In case the programer used, e.g avrdude, doesn't
# accept the same MCU name as avr-gcc (for example
# for ATmega8s, avr-gcc expects 'atmega8' and
# avrdude requires 'm8')
PROGRAMMER_MCU = $(MCU)
# Source files
# List C/C++/Assembly source files:
# (list all files to compile, e.g. 'a.c b.cpp as.S'):
# Use .cc, .cpp or .C suffix for C++ files, use .S
# (NOT .s !!!) for assembly source code files.
PRJSRC = main.c \
utils.c
# additional includes (e.g. -I/path/to/mydir)
INC =
# libraries to link in (e.g. -lmylib)
LIBS =
# Optimization level,
# use s (size opt), 1, 2, 3 or 0 (off)
OPTLEVEL = s
### You should not have to touch anything below this line ###
PATH := /Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR\ Builder.app/Contents/Resources/avrchain/bin:/usr/bin:/bin:$(PATH)
CPATH := /Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR\ Builder.app/Contents/Resources/avrchain/include
# HEXFORMAT -- format for .hex file output
HEXFORMAT = ihex
# compiler
CFLAGS = -I. $(INC) -g -mmcu=$(MCU) -O$(OPTLEVEL) \
-fpack-struct -fshort-enums \
-funsigned-bitfields -funsigned-char \
-Wall -Wstrict-prototypes \
-Wa,-ahlms=$(firstword \
$(filter %.lst, $(<:.c=.lst)))
# c++ specific flags
CPPFLAGS = -fno-exceptions \
-Wa,-ahlms=$(firstword \
$(filter %.lst, $(<:.cpp=.lst)) \
$(filter %.lst, $(<:.cc=.lst)) \
$(filter %.lst, $(<:.C=.lst)))
# assembler
ASMFLAGS = -I. $(INC) -mmcu=$(MCU) \
-x assembler-with-cpp \
-Wa,-gstabs,-ahlms=$(firstword \
$(<:.S=.lst) $(<.s=.lst))
# linker
LDFLAGS = -Wl,-Map,$(TRG).map -mmcu=$(MCU) \
-lm $(LIBS)
##### executables ####
CC=avr-gcc
OBJCOPY=avr-objcopy
OBJDUMP=avr-objdump
SIZE=avr-size
AVRDUDE=avrdude
REMOVE=rm -f
##### automatic target names ####
TRG=$(PROJECTNAME).out
DUMPTRG=$(PROJECTNAME).s
HEXROMTRG=$(PROJECTNAME).hex
HEXTRG=$(HEXROMTRG) $(PROJECTNAME).ee.hex
# Start by splitting source files by type
# C++
CPPFILES=$(filter %.cpp, $(PRJSRC))
CCFILES=$(filter %.cc, $(PRJSRC))
BIGCFILES=$(filter %.C, $(PRJSRC))
# C
CFILES=$(filter %.c, $(PRJSRC))
# Assembly
ASMFILES=$(filter %.S, $(PRJSRC))
# List all object files we need to create
OBJDEPS=$(CFILES:.c=.o) \
$(CPPFILES:.cpp=.o) \
$(BIGCFILES:.C=.o) \
$(CCFILES:.cc=.o) \
$(ASMFILES:.S=.o)
# Define all lst files.
LST=$(filter %.lst, $(OBJDEPS:.o=.lst))
# All the possible generated assembly
# files (.s files)
GENASMFILES=$(filter %.s, $(OBJDEPS:.o=.s))
.SUFFIXES : .c .cc .cpp .C .o .out .s .S \
.hex .ee.hex .h .hh .hpp
# Make targets:
# all, disasm, stats, hex, writeflash/install, clean
all: $(TRG)
$(TRG): $(OBJDEPS)
$(CC) $(LDFLAGS) -o $(TRG) $(OBJDEPS)
#### Generating assembly ####
# asm from C
%.s: %.c
$(CC) -S $(CFLAGS) $< -o $#
# asm from (hand coded) asm
%.s: %.S
$(CC) -S $(ASMFLAGS) $< > $#
# asm from C++
.cpp.s .cc.s .C.s :
$(CC) -S $(CFLAGS) $(CPPFLAGS) $< -o $#
#### Generating object files ####
# object from C
.c.o:
$(CC) $(CFLAGS) -c $< -o $#
# object from C++ (.cc, .cpp, .C files)
.cc.o .cpp.o .C.o :
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $#
# object from asm
.S.o :
$(CC) $(ASMFLAGS) -c $< -o $#
#### Generating hex files ####
# hex files from elf
.out.hex:
$(OBJCOPY) -j .text \
-j .data \
-O $(HEXFORMAT) $< $#
.out.ee.hex:
$(OBJCOPY) -j .eeprom \
--change-section-lma .eeprom=0 \
-O $(HEXFORMAT) $< $#
#### Information ####
info:
#echo PATH:
#echo "$(PATH)"
$(CC) -v
which $(CC)
#### Cleanup ####
clean:
$(REMOVE) $(TRG) $(TRG).map $(DUMPTRG)
$(REMOVE) $(OBJDEPS)
$(REMOVE) $(LST)
$(REMOVE) $(GENASMFILES)
$(REMOVE) $(HEXTRG)
error
JUSTINs-MacBook-Air:Untitled justinzaun$ make
avr-gcc -I. -g -mmcu=atmega640 -Os -fpack-struct -fshort-enums -funsigned-bitfields -funsigned-char -Wall -Wstrict-prototypes -Wa,-ahlms=main.lst -c main.c -o main.o
make: avr-gcc: No such file or directory
make: *** [main.o] Error 1
JUSTINs-MacBook-Air:Untitled justinzaun$
If I change my CC= to include the full path:
CC=/Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR\ Builder.app/Contents/Resources/avrchain/bin/avr-gcc
then it finds it, but this doesn't seem the correct way to do things. For instance its trying to use the system as not the one in the correct path.
update - Just to be sure, I'm adding the output of my ls command too so everyone knows the file exist. Also I've added a make info target to the makefile and showing that output as well.
JUSTINs-MacBook-Air:Untitled justinzaun$ ls /Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR\ Builder.app/Contents/Resources/avrchain/bin
ar avr-elfedit avr-man avr-strip objcopy
as avr-g++ avr-nm avrdude objdump
avr-addr2line avr-gcc avr-objcopy c++ ranlib
avr-ar avr-gcc-4.6.3 avr-objdump g++ strip
avr-as avr-gcov avr-ranlib gcc
avr-c++ avr-gprof avr-readelf ld
avr-c++filt avr-ld avr-size ld.bfd
avr-cpp avr-ld.bfd avr-strings nm
JUSTINs-MacBook-Air:Untitled justinzaun$
Output of make info with the \ in my path
JUSTINs-MacBook-Air:Untitled justinzaun$ make info
PATH:
/Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR\ Builder.app/Contents/Resources/avrchain/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
avr-gcc -v
make: avr-gcc: No such file or directory
make: *** [info] Error 1
JUSTINs-MacBook-Air:Untitled justinzaun$
Output of make info with the \ not in my path
JUSTINs-MacBook-Air:Untitled justinzaun$ make info
PATH:
/Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR Builder.app/Contents/Resources/avrchain/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
avr-gcc -v
make: avr-gcc: No such file or directory
make: *** [info] Error 1
JUSTINs-MacBook-Air:Untitled justinzaun$
update - When I have my CC set to include the full path as described above, this is the result of make info.
JUSTINs-MacBook-Air:Untitled justinzaun$ make info
PATH:
/Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR Builder.app/Contents/Resources/avrchain/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
/Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR\ Builder.app/Contents/Resources/avrchain/bin/avr-gcc -v
Using built-in specs.
COLLECT_GCC=/Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR Builder.app/Contents/Resources/avrchain/bin/avr-gcc
COLLECT_LTO_WRAPPER=/Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR Builder.app/Contents/Resources/avrchain/bin/../libexec/gcc/avr/4.6.3/lto-wrapper
Target: avr
Configured with: /Users/justinzaun/Development/AVRBuilder/Packages/gccobj/../gcc/configure --prefix=/Users/justinzaun/Development/AVRBuilder/Packages/gccobj/../build/ --exec-prefix=/Users/justinzaun/Development/AVRBuilder/Packages/gccobj/../build/ --datadir=/Users/justinzaun/Development/AVRBuilder/Packages/gccobj/../build/ --target=avr --enable-languages=c,objc,c++ --disable-libssp --disable-lto --disable-nls --disable-libgomp --disable-gdbtk --disable-threads --enable-poison-system-directories
Thread model: single
gcc version 4.6.3 (GCC)
which /Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR\ Builder.app/Contents/Resources/avrchain/bin/avr-gcc
/Users/justinzaun/Library/Developer/Xcode/DerivedData/AVR_Builder-gxiykwiwjywvoagykxvmotvncbyd/Build/Products/Debug/AVR Builder.app/Contents/Resources/avrchain/bin/avr-gcc
JUSTINs-MacBook-Air:Untitled justinzaun$
I tried your example on OSX and Linux, and got the same results that you did. I don't quite understand why that isn't working (and would love to know), but I do have two workarounds that might help.
export SHELL
Instead of setting the PATH in your Makefile, override the SHELL like this:
export SHELL=/Users/whatever/avr-dir/wrapper
Here's a possible version of that wrapper:
#!/bin/bash
PATH="/Users/whatever/avr-dir:${PATH}"
/bin/bash "$#"
Make will invoke this wrapper to run each line of yoru recipes. This is a little ugly, but it did work for me on OSX.
Outside
Fix the PATH outside of make. Perhaps create a script that you run once per login that fixes the PATH in your shell, or create a small script (I usually call it mk) that fixes the PATH and then invokes make passing along any parameters. Here's an exmaple:
#!/bin/bash
PATH="/Users/whatever/avr-dir:${PATH}" exec make "$#"
I know you asked for a Makefile solution, but I thought I would mention this option anyway. It is just my opinion, but things like PATHs tend to be machine specific (and not project specific), and I prefer to keep them separate from source code.
Your problem is not that make failed to find avr-gcc. Your problem is in this line:
$(CC) $(CFLAGS) -mmcu=$(MCU) -c $(input) -o $(output)
Since $(input) and $(output) have not been defined your avr-gcc command-line is incomplete. Try changing that line to this instead:
$(CC) $(CFLAGS) -mmcu=$(MCU) -c $< -o $#
$< and $# are automatic variables defined to mean "the first prerequisite" and "the output target", respectively.
The problem is that make is failing to find avr-gcc, and it's due to the \ in your PATH= line.
$ mkdir /tmp/foo\ bar
$ cd /tmp/foo\ bar
$ (echo "#! /bin/sh"; echo "echo this got run") > execable
$ chmod +x execable
$ mkdir /tmp/tstmake; cd /tmp/tstmake
(now make a Makefile with contents as shown)
$ cat Makefile
PATH := /tmp/foo\ bar:$(PATH)
all:
#echo path is "$(PATH)"
execable
$ make
path is /tmp/foo\ bar:/Users/torek/bin.i386:/Users/torek/scripts:[snipped lots]
execable
make: execable: Command not found
make: *** [all] Error 127
$ ed Makefile
71
1s/\\//p
PATH := /tmp/foo bar:$(PATH)
w
70
q
$ make
path is /tmp/foo bar:/Users/torek/bin.i386:/Users/torek/scripts:[snipped lots]
execable
this got run
Update: this is not the only problem, at least when I use my MBP to simulate the issue. The remaining two are:
CPATH also needs the backslash removed (this is a general rule about these := settings)
CPATH needs to be explicitly exported, by adding the line
export CPATH
to the Makefile.
(The reason you need the backslash sometimes, but not other times, has to do with how many times the string gets passed expliclty to the shell: once when it's in $(CC) but zero times when it is an environment variable or part of $(PATH).)
Seeing as this page didn't have a proper answer, I'll link to this page that does:
How I could add dir to $PATH in Makefile?
For whatever reason OS X does not export PATH unless you set the SHELL variable too.
So:
SHELL=/bin/bash
export PATH:=/foo/bar:$(PATH)
..would work.
I just recently ran into this issue. As other comments suggest, the version of make shipped with MacOS has some issues. Build (as #MadScientist suggests above) or install GNU make from Homebrew. The installed version of make on my system is 3.81 and exhibits the same problem. The version provided from Homebrew (version 4.3) works as expected.
I presume you're using OSX. Figuring out an elegant solution may take a few iterations.
In the meantime try this kludge, and tell us the result:
CC=`avr-gcc`
If what you want is to update your PATH variable, then do:
export PATH=$(shell echo $${PATH}):<paths to add>
Example I did:
File : ./c/luckme.sh
echo "Hello Lucky Me ! "
Makefile :
export PATH=$(shell echo $${PATH}):c:.
all:
#luckyme.sh
output of make:
~$ make
Hello Lucky Me !

tell if make is running on windows or linux

Is there a way to know in makefiles if GNU make is running on a linux OS or a windows OS?
I've built a bash script that generates a makefile for building my app and it works fine on my Debian machine. I want to try to build it on MinGW/MSYS, but the problem is that I have to build and run some test programs that check errors in source code, and to run it on Windows, I must add the .exe suffix.
uname command should give you the basic info about the OS. Can you use that, and then make an IF based on the return value?
As not to rewrite everything, here - these two questions may be of some interest to you
1. OS detecting makefile
2. Makefile that distincts between Windows and Unix-like systems
UPDATE
Please read this similar but better answer:
https://stackoverflow.com/a/14777895/938111
make (and gcc) can be easily installed on MS-Windows using Cygwin or MinGW.
As #ldigas says, make can detect the platform using UNAME:=$(shell uname) (the command uname is also installed by Cygwin or MinGW installer).
Below, I provide a complete example based on make (and gcc) to explain how to build a shared library: *.so or *.dll depending on the platform.
The example is basic/simple to be easily understandable :-)
Let's see the five files:
├── app
│ └── Makefile
│ └── main.c
└── lib
└── Makefile
└── hello.h
└── hello.c
The Makefiles
app/Makefile
app.exe: main.o
gcc -o $# $^ -L../lib -lhello
# '-o $#' => output file => $# = the target file (app.exe)
# ' $^' => no options => Link all depended files
# => $^ = main.o and other if any
# '-L../lib' => look for libraries in directory ../lib
# '-lhello => use shared library hello (libhello.so or hello.dll)
%.o: %.c
gcc -o $# -c $< -I ../lib
# '-o $#' => output file => $# = the target file (main.o)
# '-c $<' => COMPILE the first depended file (main.c)
# '-I ../lib' => look for headers (*.h) in directory ../lib
clean:
rm -f *.o *.so *.dll *.exe
lib/Makefile
UNAME := $(shell uname)
ifeq ($(UNAME), Linux)
TARGET = libhello.so
else
TARGET = hello.dll
endif
$(TARGET): hello.o
gcc -o $# $^ -shared
# '-o $#' => output file => $# = libhello.so or hello.dll
# ' $^' => no options => Link all depended files => $^ = hello.o
# '-shared' => generate shared library
%.o: %.c
gcc -o $# -c $< -fPIC
# '-o $#' => output file => $# = the target file (hello.o)
# '-c $<' => compile the first depended file (hello.c)
# '-fPIC' => Position-Independent Code (required for shared lib)
clean:
rm -f *.o *.so *.dll *.exe
The source code
app/main.c
#include "hello.h" //hello()
#include <stdio.h> //puts()
int main()
{
const char* str = hello();
puts(str);
}
lib/hello.h
#ifndef __HELLO_H__
#define __HELLO_H__
const char* hello();
#endif
lib/hello.c
#include "hello.h"
const char* hello()
{
return "hello";
}
The build
Fix Makefiles copy (replace leading spaces by tabulation).
> sed -i 's/^ */\t/' */Makefile
The make command is the same on both platforms. This is the output on MS-Windows (removed unnecessary lines).
> cd lib
> make clean
> make
gcc -o hello.o -c hello.c -fPIC
gcc -o hello.dll hello.o -shared
> cd ../app
> make clean
> make
gcc -o main.o -c main.c -I ../lib
gcc -o app.exe main.o -L../lib -lhello
The run
The application requires to know where is the shared library.
On MS-Windows, the simple/basic/stupid way is to copy the library where the application is:
> cp -v lib/hello.dll app
`lib/hello.dll' -> `app/hello.dll'
On Linux, use the LD_LIBRARY_PATH environment variable:
> export LD_LIBRARY_PATH=lib
The run command line and output are the same on both platforms:
> app/app.exe
hello

My makefile builds dependency files when not required - why?

I'm trying to create a generic makefile to build static libraries that my project uses. I've used the expertise on this site, as well as the GNU Make manual to help write the following makefile. It is working well apart from one annoying problem.
# Generic makefile to build/install a static library (zlib example)
ARCH = linux
CFLAGS = -O3 -Wall
# List of source code directories
SOURCES = src test utils
# List of header files to install
INCLUDES = src/zlib.h src/zconf.h
# Library to create
LIBNAME = libz.a
############################################################
BUILD_DIR = build/$(ARCH)
# Full path to the built library
TARGET = $(BUILD_DIR)/$(LIBNAME)
prefix = ../..
exec_prefix = prefix
libdir = $(prefix)/lib/$(ARCH)
includedir = $(prefix)/include
INSTALL_PROGRAM = install -D
INSTALL_DATA = $(INSTALL_PROGRAM) -m 644
CFILES := $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.c))
OBJECTS := $(addprefix $(BUILD_DIR)/,$(CFILES:.c=.o))
DEPENDS := $(OBJECTS:.o=.d)
.PHONY: all installdirs install uninstall clean
# Default
all: $(DEPENDS) $(TARGET)
# Build the dependency files
# (GNU Make Manual 4.14 Generating Prerequisites Automatically)
$(BUILD_DIR)/%.d: $(BUILD_DIR)
#echo "build dep for $*.c as $#"
#$(CC) -M $(CFLAGS) $*.c > $#.tmp
#sed s~.*:~"$(BUILD_DIR)/$*.o $#:"~ $#.tmp > $#
#rm $#.tmp
# Link all changed object files into static library
$(TARGET): $(OBJECTS)
$(AR) -rc $(TARGET) $?
# Compile C source to object code
$(BUILD_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
# Create the necessary directory tree for the build
$(BUILD_DIR):
#for p in $(SOURCES); do mkdir -p $(BUILD_DIR)/$$p; done
# Create the necessary directory tree for installation
installdirs:
#mkdir -p $(libdir)
#mkdir -p $(includedir)
# Install the library and headers
install: all installdirs
$(INSTALL_DATA) $(TARGET) $(libdir)
for p in $(INCLUDES); do $(INSTALL_DATA) $$p $(includedir); done
# Remove the library and headers
uninstall:
rm -f $(libdir)/$(LIBNAME)
for p in $(notdir $(INCLUDES)); do rm -f $(includedir)/$$p; done
# Remove all build files
clean:
rm -fr $(BUILD_DIR)
# Pull in the dependencies if they exist
# http://scottmcpeak.com/autodepend/autodepend.html
-include $(DEPENDS)
The problem is that the dependency files are built when they don't need to be. e.g. make install shown below rebuilds the .d files before installing.
$make --version
GNU Make 3.81
$make
build dep for utils/utils.c as build/linux/utils/utils.d
build dep for test/test.c as build/linux/test/test.d
build dep for src/zutil.c as build/linux/src/zutil.d
...
{ continues on making the other .d files, then the .o files }
...
cc -O3 -Wall -c src/zutil.c -o build/linux/src/zutil.o
cc -O3 -Wall -c test/test.c -o build/linux/test/test.o
cc -O3 -Wall -c utils/utils.c -o build/linux/utils/utils.o
ar rc { ... .o files ... }
All good up to this point! But a 'make install' now will rebuild the .d files
$make install
build dep for utils/utils.c as build/linux/utils/utils.d
build dep for test/test.c as build/linux/test/test.d
build dep for src/zutil.c as build/linux/src/zutil.d
{ ... }
install -D -m 644 build/linux/libz.a ../../lib/linux
for p in src/zlib.h src/zconf.h; do install -D -m 644 $p ../../include; done
I tried to 'touch' the .d files when the objects are built, so the update time is newer than the .o files, but that had no effect. What's wrong with my makefile?
The problem is that you include the dependency files (whatever.d), and you also have a rule for building these files. So every time you use this makefile, no matter what target you specify, it will rebuild them, include them, and execute again.
Try this for an approach to dependency handling that solves this problem. Basically, you don't need a separate rule for foo.d, just make it a side effect of the foo.o rule (it takes some thought to realize that this will work).

Resources