Different Platform Support using Makefile - makefile

I have a application running on both Linux & Mac.
Now, for this application I need to copy some libraries from different path.
For Linux,
cp ../gccRelease/libMsSipRelease.a ../../VoipAppLinux/lib/
For Mac,
cp ../DerivedData/MsSipLib/Build/Products/Debug/libMsSipLib.dylib ../../VoipAppLinux/lib/
As you can see both paths are different.
Now, my question is can I use #ifdef Linux or #ifdef APPLE in make file. If can what is the syntax please?
If #ifdef is not possible to use in makefile than how can I solve this problem.
Thank you.

You could use ifdef APPLE, but there's a more automatic way: in a makefile, a command like $(shell uname -s) will tell Make what the OS is. Try this:
OS := $(shell uname -s)
ifeq ($(OS),Linux)
MSSIPLIB := ../gccRelease/libMsSipRelease.a
else
MSSIPLIB := ../DerivedData/MsSipLib/Build/Products/Debug/libMsSipLib.dylib
endif
# And later on
cp $(MSSIPLIB) ../../VoipAppLinux/lib/

Related

How to read file contents as list of variables?

I have some python code which works with a C library that I compile with a Makefile. So I create some install/uninstall/installed routines to load/unload/check my library. I add the python commands to it too so everything works.
Now the problem is, not all the machines have the same python version and python might not be set to the most up to date version. I would like to execute python-{x.y} -m pip {install -e . | uninstall {libname} | show {libname}}.
My current approach was:
create a configured.dat file with the following contents:
python3.4 python3.6 python3.8
And the following Makefile routine:
CONFIGURED_FILE=configured.dat
INSTALLED_PYTHON_VERSIONS :=$(file < $(CONFIGURED_FILE))
RED := \033[0;31m
GREEN := \033[1;32m
CYAN := \033[0;36m
NO_COLOR := \033[0m
ifneq ($(VERBOSE),)
VERBOSE := ''
else
VERBOSE := '-q'
endif
EDITABLE := '-e'
.PHONY: install
install:
# make C libs
$(foreach f,$(INSTALLED_PYTHON_VERSIONS), echo -e 'installing $(CYAN)$f$(NO_COLOR)'; $f -m pip install $(VERBOSE) $(EDITABLE) .;)
On my development machine this works. On my deployment machine it doesn't. The variable INSTALLED_PYTHON_VERSIONS is empty. How? Why? The only change I found between the environments that should impact it is the make version, 3.82 on prod, and 4.3 on dev. Prod is centos 7.9.2009 and dev is ubuntu 22.04.1.
The root problem is the wanting to invoke different python versions, the superficial problem is being unable to read the file contents into a list of variables. A good answer to either would be fine by me.
You found the problem yourself: on one machine you're using GNU make 3.82 and on the other 4.3. According to the GNU make NEWS file, the $(file ...) function was added in GNU make 4.0 (released in 2013, so 9 years ago).
You can just use cat:
INSTALLED_PYTHON_VERSIONS := $(shell cat $(CONFIGURED_FILE))
I should also point out that echo -e is not portable. There are no POSIX-specified options to echo and lots of different implementations accept, or not, different options. You probably want to switch to printf which is portable and well-defined.

Check executable is on a specific path in Makefile

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.

Makefile internal command on linux functional but not macos

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 ...

Does GNU Make have a way to open a file using the default program?

I've come across this question whenever I want a make command to display a file that resulted from following a particular recipe using the operating system's default application for opening that type of file.
For example... I work primarily in Linux. I can generate and view documentation of my code with make docs where I have put the following in my Makefile:
docs:
cd ${DIR_WORKING}/doc/; doxygen Doxyfile
xdg-open ${DIR_WORKING}/doc/html/index.html &
I want to use make docs in Windows and have the same effect. I could alternatively use a user-assigned variable like a $(OPEN) in place of xdg-open. Is there a way to open a file using the default program in Windows and Linux without requiring the user to modify the Makefile? I've never used Autoconf for my codes and hope there is a solution that doesn't depend on going in that direction.
You could consider doing OS detection and in your Makefile initialize the OPEN variable depending on the OS.
ifeq ($(OS),Windows_NT)
OPEN := start
else
UNAME := $(shell uname -s)
ifeq ($(UNAME),Linux)
OPEN := xdg-open
endif
...
In your target:
docs:
cd ${DIR_WORKING}/doc/; doxygen Doxyfile
$(OPEN) ${DIR_WORKING}/doc/html/index.html &
I looked at the following answers for some inspiration with this one.
OS detecting makefile
Open file from the command line on Windows
Here is a Makefile snippet using MAKE_HOST as per user657267.
LINUX:=$(findstring linux,$(MAKE_HOST))
ifeq ($(LINUX),linux)
VDSO_PARSE:=parse_vdso.c
endif
In my case, I was testing time functionality under msys and wsl2 and wanted to minimize library overhead by calling get_time_of_day directly. For the OP, the OS by itself is not enough to guarantee that applications are installed, but this is conceptually as good as the accepted answer and maybe useful to someone.

Command line arguments to make for working in Linux and Windows

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.

Resources