Search code examples
linuxmakefilebakefile

Escaping a system variable to pass as an argument to make


I have a makefile generated by bakefile which is working fine. To run the executable it needs libraries from a different folder. I found the command rpath used to specify the path to these library. But I have to send it to the makefile as an argument when using the command. I cannot specify it directly from the bakefile.

I can use the LDFLAGS arguments which is fine. And I found here how to use the $ORIGIN variable.

My question is how does this escaping works?

make LDFLAGS="-Wl,-rpath '-Wl,\$\$ORIGIN'"

Is the single quote to prevent make to interpret the variable? And why the \$ is here twice?


Solution

  • Yeesh. What a mess.

    So, the first set of quotes is removed by the shell, before it starts the make command. Since the outer set of quotes is double-quotes, you have to escape the $ otherwise the shell will treat it as a shell variable (compare to a command like echo "my path is $PWD" and how the PWD variable is expanded). The shell uses backslashes to quote things like $.

    So, by the time the shell hands the command line to make, it sees the setting LDFLAGS=-Wl,-rpath '-Wl,$$ORIGIN'

    Next in your makefile will be a recipe with a command like this:

    $(LD) $(LDFLAGS) ...
    

    Make will expand the LDFLAGS variable as above. For make, any name preceded by a $ is considered a make variable and you escape it from expansion by make by doubling the $ (not using backslashes like the shell), and writing $$. Make will remove one $ during expansion.

    So, make will reduce LDFLAGS to the string -Wl,-rpath '-Wl,$ORIGIN' and pass that to the shell.

    The shell will strip the next level of quoting, which in this case is the single quotes. Variables are not expanded inside single quotes, so the linker actually gets arguments, literally, -Wl,-rpath and -Wl,$ORIGIN, which is what you want.