简体   繁体   English

如何避免 GNU Make 和 shell 在定义变量时解开逗号和撇号

[英]How to avoid both GNU Make and shell from unwrapping the commas and apostrophes when defining variables

I have a variable called SELF in my makefile that I want to pass to my GCC compiler through the -D option to define a macro.我的 makefile 中有一个名为SELF的变量,我想通过-D选项将其传递给我的 GCC 编译器来定义宏。 This macro can only have a single character in [0-9a-zA-Z] - but this is another problem in itself I won't try to discuss here -.这个宏在 [0-9a-zA-Z] 中只能有一个字符——但这本身就是另一个问题,我不会在这里讨论——。 I'm having trouble to find a workaround for avoiding both GNU Make and the shell to remove the commas in the definition.我很难找到一种解决方法来避免 GNU Make 和 shell 删除定义中的逗号。 An example how it is defined would be:它是如何定义的一个例子是:

#include <stdio.h>

#define str(x) #x
#define xstr(x) str(x)
    
#ifndef SELF  
# define SELF '0'
#endif
#pragma message("SELF is: " xstr(SELF))

int main(void){
    return 0;
}

The makefile looks like this:生成文件如下所示:

CC = gcc
WFLAGS = -Wall -Wextra

ifdef SELF
DSELF = -DSELF=$(SELF)
endif
CFLAGS = -std=c99 $(DSELF)

all: clean test

%: %.o

.PHONY: clean
clean:
    -rm -v test

If you execute the makefile with make , a note will appear that will tokenize the definition of SELF :如果您使用make执行 makefile ,则会出现一条注释,将标记化SELF的定义:

test.c:9:9: note: ‘#pragma message: SELF is: '0'’
    9 | #pragma message("SELF is: " xstr(SELF))
      |         ^~~~~~~

On the other hand, executing make SELF='0' will destroy the apostrophes, as you can see in the verbose output of GNU Make:另一方面,执行make SELF='0'将破坏撇号,正如您在 GNU Make 的详细输出中所看到的:

gcc -std=c99 -DSELF=0    test.c   -o test

If you try to wrap the apostrophes with quotes, like make SELF="'0'" , the definition will pass to GCC, but even the shell removes the apostrophes since the #pragma message will still display 0 .如果您尝试用引号将撇号括起来,例如make SELF="'0'" ,则定义将传递给 GCC,但即使 shell 也会删除撇号,因为 #pragma 消息仍将显示0 BUT if you execute directly gcc -std=c99 -DSELF="'0'" test.c -o test , the definition will be successfully be done:但是如果你直接执行gcc -std=c99 -DSELF="'0'" test.c -o test ,定义将成功完成:

test.c:9:9: note: ‘#pragma message: SELF is: '0'’
    9 | #pragma message("SELF is: " xstr(SELF))
      |         ^~~~~~~

How can you avoid all this from happening?你怎么能避免这一切的发生? Does this mean you can't define string of the same sorts?这是否意味着您不能定义相同类型的字符串?

Your question is very confusing because at first you're talking about commas, then you start talking about apostrophes which are completely different.你的问题非常令人困惑,因为一开始你在谈论逗号,然后你开始谈论完全不同的撇号。

In computer-ese, we generally call the ' character a "single quote", not an apostrophe, which often refers to a different character in a full character set.在计算机语言中,我们通常将'字符称为“单引号”,而不是撇号,它通常指的是完整字符集中的不同字符。

Anyway, since neither the shell nor make care about commas I can only assume you meant single quotes throughout your question.无论如何,由于 shell 也不关心逗号,我只能假设您在整个问题中都指的是单引号。

The answer is, make doesn't care about quotes at all and won't strip them.答案是, make 根本不关心引号,也不会剥离它们。 But, the shell very much does care about them and will strip them for you: it's important to understand that the shell removes quotes before it starts the program, so the program has no chance to even know whether the quotes existed or not.但是,shell 非常关心它们,并且会为您去除它们:重要的是要了解 shell启动程序之前删除引号,因此程序甚至没有机会知道引号是否存在。 Take your first example:拿你的第一个例子:

make SELF='0'

Here, the shell will remove the quotes before invoking make.在这里,shell 将在调用 make 之前删除引号。 Make cannot know whether you ran make SELF=0 or make SELF='0' because by the time make is invoked, the quotes are removed. Make 无法知道您是运行make SELF=0还是make SELF='0'因为在调用 make 时,引号已被删除。

Then, when make runs a shell command to start the compiler, that shell command will also remove quotes before the compiler is invoked.然后,当化妆运行shell命令来启动编译器,是shell命令将被调用编译器之前删除引号。 So you have a command like this that make runs:所以你有一个这样的命令可以运行:

gcc -std=c99 -DSELF='0'    test.c   -o test

the shell removes the quotes and the compiler will get the argument -DSELF=0 . shell 删除引号,编译器将获得参数-DSELF=0

How do you defend against this?你如何防御? You need to escape the quotes.您需要转义引号。 In your situation you want to preserve the single quotes so you need to either use backslashes or double quotes around them (as you've found).在您的情况下,您希望保留单引号,因此您需要在它们周围使用反斜杠或双引号(如您所见)。

It's not exactly clear what you want to do, but assuming you'd like to be able to run make like this:目前还不清楚您想要做什么,但假设您希望能够像这样运行 make:

make SELF=0

then you'll need to add both the single quotes and escape them in the makefile.那么您需要添加两个单引号并将它们转义到 makefile 中。 You can put those into your makefile like this:您可以像这样将它们放入您的 makefile 中:

ifdef SELF
DSELF = -DSELF="'$(SELF)'"
endif
CFLAGS = -std=c99 $(DSELF)

Now the compiler will be invoked with -DSELF="'0'" , then shell will remove the outer quotes, and your program will be invoked with -DSELF='0' which is what you want.现在将使用-DSELF="'0'"调用编译器,然后 shell 将删除外部引号,并且您的程序将使用-DSELF='0'调用,这正是您想要的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM