I just stumbled on this problem. I tried to write a very basic Makefile
target:
core: myprogram
ulimit -c 10000
./myprogram
ulimit -c 0
The idea is to set up the core size limit to a proper value, make the program crash and then reset the core size limit back to zero. When I am calling this rule, I get the following error message:
$ make core
cc -Wall -Wextra -m32 -g -o example example.c
ulimit -c 100000
make: ulimit: Command not found
make: *** [core] Error 127
First, I have been a bit surprised, but I think that the problem is coming from the fact that ulimit
is a shell builtin. And, suprisingly (at least for me), these builtin functions cannot be called from a Makefile
.
Moreover, ulimit
can be both a builtin function only (it is the case on my Debian) or a binary program only (/usr/bin/ulimit
).
So, my question is simple, how to workaround this problem, if possible in an elegant and portable manner, and call the builtin function from the inside of a Makefile ?
In the official GNU make document(http://www.gnu.org/software/make/manual/make.html) Chapter 5.3.2, it says "The program used as the shell is taken from the variable SHELL. If this variable is not set in your makefile, the program /bin/sh is used as the shell. " You can set SHELL to /bin/bash.
The default shell for any
Makefile
issh
. If you have to use builtins of a specific shell, specify that shell in yourMakefile
:Note that this is bad practice, because the idea is that your
Makefile
should work on any machine, not only those withbash
installed.If you want to support either variant (external vs. builtin), you can check for the availability of
bash
resp.ulimit
viawhich
, and set a variable containing the command to use (ulimit
vs.bash -c "ulimit"
) depending on the outcome of that check.Edit: MadScientist is absolutely right about the "current shell only" aspect of
ulimit
. I'll keep this answer intact for documentation purposes, but it doesn't help with perror's specific problem.Short answer: add a semicolon (;) on the end of the command. In this way you will invoke FULL shell with builtin tools.
instead of
The reason you're getting this error is that make (GNU make in particular) tries to perform a number of optimizations. One of those is that if the command appears to be a simple command that does not require the shell, then make will simply invoke it directly via fork/exec and not run a shell. If the command only exists as a shell built-in, then this will not work. Your command line
ulimit -c 10000
is a simple command and ulimit is not defined as only a shell-builtin that make knows about, so make will try to fork/execulimit
directly. So a way to get around your immediate issue is to simply add a character that's special to the shell (the most obvious one is;
), which will hint to make that this command needs to be sent to the shell.However, this will not work for you.
Exactly contrary to H2CO3's comment above: How possibly could it be [a shell builtin], given the functionality it provides? the real question you have to ask yourself is the opposite: how possibly could it NOT be one, given the functionality it provides? The man page for ulimit clearly states: The ulimit utility shall set or report the file-size writing limit imposed on files written by the shell and its child processes, and further: Since ulimit affects the current shell execution environment, it is always provided as a shell regular built-in.
You have to remember that it's virtually impossible for a process in UNIX to modify ANY aspect of its parent process. It can only modify itself, or any child processes that it invokes. This includes the environment variables, working directory, and it also includes ulimit settings.
So, good, how does this apply to your situation? You have to remember that each logical line in a make recipe is invokes in a separate shell. So for a command like:
(adding the semicolons to force a shell) what make basically invokes is this:
As you can see, each ulimit is invoked in its own shell, so it's effectively useless. It will modify the core file size limit for that shell, then the shell exits and the change is lost, then your program is invoked in a new shell with the original ulimit, then a third shell is invoked and ulimit for cores is set to 0 (also useless).
What you need to do is put all of these commands on a single logical line, like this:
(you don't need to set the limit back, because the shell will exit anyway).
As a side note, this is why make doesn't worry too much about these shell builtins. A builtin like this is basically impossible to use to any effect in a context where you don't need to use some special shell character like a semicolon.
You can say: