Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write the 'cd' command in a makefile?

For example, I have something like this in my makefile:

all:      cd some_directory 

But when I typed make I saw only 'cd some_directory', like in the echo command.

like image 507
Davit Siradeghyan Avatar asked Nov 24 '09 11:11

Davit Siradeghyan


People also ask

How do I make a cd in makefile?

As noted in the comments, you should use '&&' to join commands, which means they only get executed if the preceding command was successful. This is especially crucial when doing destructive work, such as clean-up, as you'll otherwise destroy the wrong stuff, should the cd fail for whatever reason.

How do I get the current directory in makefile?

You can use shell function: current_dir = $(shell pwd) . Or shell in combination with notdir , if you need not absolute path: current_dir = $(notdir $(shell pwd)) .

What is command line cd?

The cd command, also known as chdir (change directory), is a command-line shell command used to change the current working directory in various operating systems. It can be used in shell scripts and batch files. cd / chdir.


2 Answers

It is actually executing the command, changing the directory to some_directory, however, this is performed in a sub-process shell, and affects neither make nor the shell you're working from.

If you're looking to perform more tasks within some_directory, you need to add a semi-colon and append the other commands as well. Note that you cannot use newlines as they are interpreted by make as the end of the rule, so any newlines you use for clarity needs to be escaped by a backslash.

For example:

all:         cd some_dir; echo "I'm in some_dir"; \           gcc -Wall -o myTest myTest.c 

Note also that the semicolon is necessary between every command even though you add a backslash and a newline. This is due to the fact that the entire string is parsed as a single line by the shell. As noted in the comments, you should use '&&' to join commands, which mean they only get executed if the preceding command was successful.

all:         cd some_dir && echo "I'm in some_dir" && \           gcc -Wall -o myTest myTest.c 

This is especially crucial when doing destructive work, such as clean-up, as you'll otherwise destroy the wrong stuff, should the cd fail for whatever reason.

A common usage though is to call make in the sub directory, which you might want to look into. There's a command line option for this so you don't have to call cd yourself, so your rule would look like this

all:         $(MAKE) -C some_dir all 

which will change into some_dir and execute the Makefile in there with the target "all". As a best practice, use $(MAKE) instead of calling make directly, as it'll take care to call the right make instance (if you, for example, use a special make version for your build environment), as well as provide slightly different behavior when running using certain switches, such as -t.

For the record, make always echos the command it executes (unless explicitly suppressed), even if it has no output, which is what you're seeing.

like image 171
falstro Avatar answered Sep 25 '22 21:09

falstro


Starting from GNU make 3.82 (July 2010), you can use the .ONESHELL special target to run all recipes in a single instantiation of the shell (bold emphasis mine):

  • New special target: .ONESHELL instructs make to invoke a single instance of the shell and provide it with the entire recipe, regardless of how many lines it contains.
.ONESHELL: # Applies to every targets in the file!  all:     cd ~/some_dir     pwd # Prints ~/some_dir if cd succeeded  another_rule:     cd ~/some_dir     pwd # Prints ~/some_dir if cd succeeded 

Note that this will be equivalent to manually running

$(SHELL) $(.SHELLFLAGS) "cd ~/some_dir; pwd" # Which gets replaced to this, most of the time: /bin/sh -c "cd ~/some_dir; pwd" 

Commands are not linked with && so if you want to stop at the first one that fails, you should also add the -e flag to your .SHELLFLAGS:

.SHELLFLAGS += -e 

Also the -o pipefail flag might be of interest:

If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.

like image 45
Chnossos Avatar answered Sep 24 '22 21:09

Chnossos