I have a makefile using the .ONESHELL command. This feature is supported beginning from version 3.82 of Make.
Is there a way to check and exit if the Make version is to old ?
ifeq ($(filter oneshell,$(.FEATURES)),)
$(error Your version of make does not support .ONESHELL)
endif
Related
I want to try and check an executable (in this case Python's pip) is on a specific path (the virtual environment) in the Makefile (this will be done prior to running a make command to install all the requirements, and is a safety measure to ensure they don't end up in system python by mistake).
(Also, yes, I know I can force a virtual env for pip, but this isn't just for me, so I can't guarantee that's done ...)
I've had a few attempts, but currently have this:
DIRENV := $(shell pwd)/.direnv/
PIP := $(shell which pip)
.PHONY: check-pip
check-pip:
FOUND_PIP := $(if $(findstring $(PIP),$(DIRENV)),found,)
$(info FOUND_PIP=$(FOUND_PIP))
ifeq ($(FOUND_PIP),found)
$(info Found pip on the path)
else
$(error ERROR: Cannot find pip))
endif
$(DIRENV) and $(PIP) are correct if I print them out.
There are 2 issues with this:
I can't seem to get findstring to work at all!
The ifeq runs both parts of the conditional regardless.
❯ make check-pip
FOUND_PIP=
Found pip on the path
Makefile:37: *** ERROR: Cannot find pip. Stop.
And just to clarify the make version:
❯ make --version
GNU Make 4.2.1
You have to write your check recipe using shell syntax.
.PHONY: check-pip
check-pip:
case "$(PIP)" in \
("$(DIRENV)"/*) echo "Found pip on the path" ;; \
(*) echo "Cannot find pip"; exit 1 ;; \
esac
Note, you need this if you only want to check this when the user specifically runs the check-pip target.
If you want to check it always whenever the user runs make regardless of which target they specify, then you can use makefile operations but you should not put them in a recipe, because they are run as the makefile is parsed not when a target is built. And you don't need a check-pip target at all.
Within a Makefile on linux, we can excute shell/bash commands with it to move directories or excute another files. However when porting the same Makefile over to macOS, all the commands are not readible (therefore path and execution are broken). Is there a universal command or workflow that can work on both?
Example of Makefile
.ONESHELL:
COMMAND ?= none
GIT_HASH ?= githash
alpine:
#cd images/alpine
#make ${COMMAND} GIT_HASH=${GIT_HASH} ALPINE_VERSION=3.6.5 TAG=3.6
so in a linux box both #CD and #MAKE are executed but not for macOS Catalina. I would like to make it universal so that both system will respect the appropriate command that follows.
Chances are that your MacOS box uses its default GNU make version (3.81). .ONESHELL was introduced with 3.82. Upgrade with Homebrew or MacPort. Anyway, better avoid make in recipes, prefer $(MAKE), and instead of cd; make you can use GNU make's -C option: $(MAKE) -C images/alpine ...
I want to avoid typing "-std=c++11" on the command line every time.
Is there any simple/direct solution to my question?
If you can, upgrade to GCC 6.
The default mode for C++ is now -std=gnu++14 instead of -std=gnu++98.
You can get a GCC supporting new GCC for example here:
https://nuwen.net/mingw.html
Windows has the DOSKEY command to define macros (which are analogous to Unix aliases).
Something like this should work:
doskey g++="g++ --std=c++11 $*"
A Makefile and the CXXFLAGS variable is an alternative (e.g. see Makefile c++11 support).
I have encountered errors on running the conditional assignment operator in a Makefile in Solaris 11.1. However I encounter no errors on running the same Makefile in Ubuntu.
version ?= 6.1
all:
echo $(version)
Note: Before the echo, there is a tab before the echo in the original code. Using four spaces here just for convenience of editing.
Error encountered in Solaris 11.1:
make: Fatal error in reader: Makefile, line 1: Badly formed macro assignment
However, there are no such errors on Ubuntu.
Better you use gmake because many Makefiles use Gnu-specific features. Solaris make might be using slightly different syntax. You can read the Solaris makefile manual; you will find that there is no ?= operator in it. Hence you are getting that error.
?= is a feature added by GNU make, which is the default version of make on Ubuntu, but on Solaris is installed as gmake or /usr/gnu/bin/make. ?= is not supported by the native make command on Solaris, which is installed as /usr/ccs/bin/make on older releases, /usr/bin/make on Solaris 11 and later.
If you need to use the GNU extensions in your makefiles, make sure you run the GNU make, not the Solaris make.
I have gone through the link
Passing additional variables from command line to make.
I have a project which compiles both on Linux and Windows using makefiles. In Windows it uses gcc while in Linux it uses the ARM version of gcc ie armv7-linux-gcc.
I would like to use a command line variable which tells the makefile which compiler to use depending on Windows or Linux.
For example in Windows it should have something like this:
CC= gcc
CFLAGS= -c -D COMPILE_FOR_WINDOWS
and for Linux:
CC = armv7-linux-gcc
CFLAGS = -c -D COMPILE_FOR_LINUX
These preprocessor defines COMPILE_FOR_WINDOWS and COMPILE_FOR_LINUX are present in the code base and can't be changed.
Also for make clean it should clean up both for Windows and Linux. I can't assume that I people who build this will have Cygwin installed so can't use rm for deleting files.
This answer is only valid if you're using GNU make or similar:
Conditionally set your make variables using an Environment Variable.
For the 'clean' rule to function properly, you may also have to create a make variable for any differences in file extensions for either OS.
Naive example:
ifeq ($(OS), Windows_NT)
CC=gcc
RM=del
EXE=.exe
CFLAGS=-c -DCOMPILE_FOR_WINDOWS
else
CC=armv7-linux-gcc
RM=rm
EXE=
CFLAGS=-c -DCOMPILE_FOR_LINUX
endif
PROG=thing$(EXE)
.PHONY: all
all: $(PROG)
$(CC) $(CFLAGS) -o $(PROG) main.c
.PHONY: clean
clean:
-$(RM) $(PROG) *.o
Maybe you could use ant (with a build.xml file) to build the project.
Else, in a Makefile, you would need to check the system and put some conditions to check wether you are making the project in an Unix environment or a Windows environment.