How to specify priority in makefile - gcc

I have a makefile and several targets there. I want to clean directory first, then build directories and then run compilation of tasks1..4. Sometimes building directories starts after compilation and this makes compilation impossible.
Makefile in general looks like:
release: clean
release: build
release: task1 task2
release: task3 task4
Clean and build must be finished before tasks1..4 start running. In other words how to specify priority in makefile tasks. Now seems all 4 lines from the makefile start altogether in one moment.

I'm assuming you're using -j; without parallel builds enabled make will never start any rules together: it always runs them one at a time in the order the prerequisites are listed.
The only way to specify order is via prerequisites. So, this would look like:
release: task1 task2 task3 task4
task1 task2 task3 task4: build
build: clean
However, this last step is a very bad idea: you don't want your build target to depend on clean in general, otherwise it will always be run. You can either ask people to run clean by hand, but probably the most common way to deal with release targets like this is with make recursion:
release:
$(MAKE) clean
$(MAKE) build
$(MAKE) task1 task2 task3 task4

Related

Makefile get calling rule name

I am trying to create a makefile so when calling it the syntax will be make release or make debug.
In order to do so, I have composed the following makefile:
release debug: mode := $#
release debug: build
build:
*** actual build commands using $(mode) ***
But in the making process, when reaching the build rule, $(mode) seems to be empty.
Is there a better/proper build debug and release binaries?
The '$#' automatic variable is only available when building a target. It does not have a value when a rule is evaluated. As a result '$#' is not set during the execution of the line:
release debug: mode := $#
Consider setting up rules for 'build' and 'release'
release debug:
$(MAKE) build mode=$#
build:
Or the alternative (which I think is less intuitive, but more efficient):
release: mode=release
debug: mode=debug
build:
...

How to have Gradle task depend on another task but not re-execute if the other executes?

I would like to have one Gradle task, taskA, to trigger the execution of another task, taskB, if both aren't up-to-date but the execution of taskB shouldn't trigger an execution of taskA if only taskB isn't up-to-date. How can this be done?
IOW, there are two parts of the task dependency involved here, the task hierarchy and the up-to-date checks. I would like to bed able to set up the task hierarchy but not have it imply the up-to-date check for taskA.
Context: taskA must execute if its inputs change or if taskB executes on a dev machine (ie not CI). taskB must execute if it's not up-to-date. This is because the output of taskB is an executable that's run by taskA. The reason taskA shouldn't run if only the executable is updated is because the updated executable can produce different output than the previous executable. That new output can cause issues with other parts of the build. Since the purpose of the output is to help ensure users are following best practices, the new output of the updated executable can be ignored in CI builds.
More concretely, taskA calls a protolock binary which is output by taskB. taskA outputs a proto.lock file which engineers should commit. Auto-committing that file can lead to surprises for engineers and to subversion of the purpose of these checks.
Use onlyIf:
taskB.onlyIf {
trueIffNotCiOrInputsAreNewerThanOutput()
}

Non phony target behaves like a phony target

I am working on a boot project. In my boot root directory there is a makefile that contains among other things, the following code which confuse me:
.DEFAULT_GOAL = all
.PHONY: all
all: xboot
xboot: $(TOP_DIR)/boot
#echo "Building Boot" $(TOP_DIR)
$(MAKE) -C $(TOP_DIR)/boot/src
Now, the problem is, that any time when this makefile is executed by calling make, the xboot receipt is always running. It seems that this xboot target acts like a phony target. From GNU Documentation regarding phony targets:
Phoniness is not inherited: the prerequisites of a phony target are
not themselves phony, unless explicitly declared to be so.
Means that xboot target is not a phony one, but it's receipt is always running. I could not find anywhere an explanation for that.
Project facts-
directory $(TOP_DIR)/boot contains sources and headers under $(TOP_DIR)/boot/src and $(TOP_DIR)/boot/include, directory $(TOP_DIR)/boot does not get touched at the build (it is not get updated)
Trying to understand the behavior I played around-
I tried touching $(TOP_DIR)/boot, and/or tried touching and creating file xboot file anywhere in the project, but behavior remains the same.
GNU Make 4.1
Built for x86_64-pc-linux-gnu
make is not always handling folder dependencies the way you expect.
Should use a file dependency inside $(TOP_DIR)/boot like $(TOP_DIR)/boot/.exists or, even better, all your source files with a $(wildcard ...) function.
Like:
xcode: $(widcard $(TOP_DIR)/boot/src/*.c $(TOP_DIR)/boot/src/*.h)
This will cause a rebuild only on code change.

How to configure Makefile to support build for all/multiple artifact types

What is the general best practice for creating a Makefile to support building for a specific type of artifact as well as support for building all artifact types in one command.
For example, let's say there is a Makefile which supports building of a app on a specific OS:
make app OS="Windows"
make app OS="Linux"
make app OS="Mac"
Let us say that the Makefile looks something like:
my-other-dependency:
...
# Performs commands specific to $(OS)
my-dependency: my-other-dependency
...
# Performs commands specific to $(OS)
app: my-dependency
...
# Performs commands specific to $(OS)
To build all artifacts, one can invoke these 3 commands sequentially:
make app OS="Windows"
make app OS="Linux"
make app OS="Mac"
What is a recommended structure of the Makefile to support an all in one command such as:
make app # build all artifact types (Windows, Linux, Mac)
or
make app OS="all" # build all artifact types (Windows, Linux, Mac)
Or is there something wrong with the pattern above? I am open to any suggestions. Thank you!
I would use make recursion. Create a new target like all-os or something:
.PHONY: all-os
all-os:
$(MAKE) app OS=Windows
$(MAKE) app OS=Linux
$(MAKE) app OS=Mac
ETA This is another option, that uses a separate target named for each OS to allow parallel builds:
OSLIST := Windows Linux Mac
_ostargets := $(addprefix app-,$(OSLIST))
$(_ostargets): app-%:
$(MAKE) app OS=$*
app-all: $(_ostargets)
.PHONY: app-all $(_ostargets)
You can also now run make app-Windows instead of make app OS=Windows, if you prefer.

makefile: how to compile fast

I am using GCC 4.7 and compiling my C++ code-project. The code consists of files distributed in directories.
On RHEL server I use, there are 16 cores, still the compilation speed is quite slow. Can you suggest possible alternatives or options of makefile, which may help in compiling fast. I have tried -j but it only compiles some folders and stops; does not compile the main binary.
I will be grateful for any help.
if your makefile fails when you compile with -j but works fine without, then you may need to fix your makefile to work properly with parallel compilation. Otherwise, those other 15 cores are of no use to you.
It's not uncommon for less experienced makefile writers to write something like:
final: step1 step2 step3
to mean "to build final, first build step1, then step2, then step3". This works fine when you are running with the default setup of -j 1 because make happens to build each of the dependencies in left-to-right order. But if you use -j 20 (say) then it will attempt to build them in parallel. It will attempt to start building all 3 steps at once, without first waiting until each successive step is complete.
The correct way to write this is:
final: step3
step3: step2
step2: step1
This tells make exactly what's happening: to build final you first need to build step3, for which you need step2, for which you need step1.

Resources