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

后端 未结 6 379
时光取名叫无心
时光取名叫无心 2020-11-29 14:53

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

all:
     cd some_directory

But when I typed make I saw only \'cd some

相关标签:
6条回答
  • 2020-11-29 15:02

    What do you want it to do once it gets there? Each command is executed in a subshell, so the subshell changes directory, but the end result is that the next command is still in the current directory.

    With GNU make, you can do something like:

    BIN=/bin
    foo:
        $(shell cd $(BIN); ls)
    
    0 讨论(0)
  • 2020-11-29 15:02

    To change dir

    foo: 
        $(MAKE) -C mydir
    
    multi:
        $(MAKE) -C / -C my-custom-dir   ## Equivalent to /my-custom-dir
    
    0 讨论(0)
  • 2020-11-29 15:10

    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.

    0 讨论(0)
  • 2020-11-29 15:17

    Here's a cute trick to deal with directories and make. Instead of using multiline strings, or "cd ;" on each command, define a simple chdir function as so:

    CHDIR_SHELL := $(SHELL)
    define chdir
       $(eval _D=$(firstword $(1) $(@D)))
       $(info $(MAKE): cd $(_D)) $(eval SHELL = cd $(_D); $(CHDIR_SHELL))
    endef
    

    Then all you have to do is call it in your rule as so:

    all:
              $(call chdir,some_dir)
              echo "I'm now always in some_dir"
              gcc -Wall -o myTest myTest.c
    

    You can even do the following:

    some_dir/myTest:
              $(call chdir)
              echo "I'm now always in some_dir"
              gcc -Wall -o myTest myTest.c
    
    0 讨论(0)
  • 2020-11-29 15:21

    Like this:

    target:
        $(shell cd ....); \
        # ... commands execution in this directory
        # ... no need to go back (using "cd -" or so)
        # ... next target will be automatically in prev dir
    

    Good luck!

    0 讨论(0)
  • 2020-11-29 15:25

    Starting from GNU make 3.82 (July 2010), you can use the .ONESHELL special target to run all recipe lines 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: # Only applies to all target
    all:
        cd ~/some_dir
        pwd # Prints ~/some_dir if cd succeeded
    
    another_rule:
        cd ~/some_dir
        pwd # Oops, prints ~
    
    0 讨论(0)
提交回复
热议问题