假设我想将位于/home/me/Google Drive/Foobar/
的C ++项目编译成名为Foobar
的可执行文件,我想使用GNU Make来自动完成该过程。
这是我的Makefile的样子:
OUTPUT = $(notdir $(CURDIR))
all $(OUTPUT):
g++ *.cpp -o $(OUTPUT)
问题是,由于项目路径中有空格,notdir
命令正在解释两个单独的路径并返回Google Foobar
。
我尝试在$(CURDIR)
($(notdir "$(CURDIR)")
)周围加上引号,但我收到以下错误:
/bin/sh: -c: line 0: unexpected EOF while looking for matching `"'
/bin/sh: -c: line 1: syntax error: unexpected end of file
Makefile:4: recipe for target 'all' failed
make: *** [all] Error 1
我不明白问题的来源。
另外,我希望得到一个不涉及更改路径名称的答案...谢谢:)
答案 0 :(得分:1)
您可以尝试使用space
中的_
替换$(CURDIR)
,然后获取$(OUTPUT)
。如下所示
null :=
SPACE := $(null) $(null)
OUTPUT = $(notdir $(subst $(SPACE),_,$(CURDIR)))
all $(OUTPUT):
g++ *.cpp -o $(OUTPUT)
基本上在 string substitution (subst)
$(OUTPUT) will be Foobar
答案 1 :(得分:0)
存储目录时GNU make端的问题少于shell扩展端的问题。所以改变
g++ *.cpp -o $(OUTPUT)
为:
g++ *.cpp -o "$(OUTPUT)"
使用名为remake的GNU make变体,您可能更容易看到它。
使用重制,如果您想验证$ OUTPUT的值是否有空格,您可以运行:
$ remake -X
GNU Make 4.1+dbg0.91
...
-> (/home/me/Google Drive/Makefile:3)
all:
remake<0> expand OUTPUT
Makefile:1 (origin: makefile) OUTPUT := Google Drive
现在,如果您想查看执行与GNU make相同的操作的shell脚本,请使用 write 命令:
remake<1> write all
File "/tmp/all.sh" written.
以上所有是 make 目标名称。然后查看/tmp/all.sh
这只是一个shell脚本,你会发现那里有问题,当然可以通过添加引号来修复。
答案 2 :(得分:0)
看起来这种组合在这种情况下起作用。
import argparse
import collections
import csv
import simplejson as json
def read_and_write_file(json_file_path, csv_file_path, column_names):
"""Read in the json dataset file and write it out to a csv file,given the column names."""
with open(csv_file_path, 'wb+') as fout:
csv_file = csv.writer(fout)
csv_file.writerow(list(column_names))
with open(json_file_path) as fin:
for line in fin:
line_contents = json.loads(line)
csv_file.writerow(get_row(line_contents, column_names))
def get_superset_of_column_names_from_file(json_file_path):
"""Read in the json dataset file and return the superset of column names."""
column_names = set()
with open(json_file_path) as fin:
for line in fin:
line_contents = json.loads(line)
column_names.update(
set(get_column_names(line_contents).keys())
)
return column_names
def get_column_names(line_contents, parent_key=''):
"""Return a list of flattened key names given a dict.
Example:
line_contents = {
'a': {
'b': 2,
'c': 3,
},
}
will return: ['a.b', 'a.c']
These will be the column names for the eventual csv file.
"""
column_names = []
for k, v in line_contents.iteritems():
column_name = "{0}.{1}".format(parent_key, k) if parent_key else k
if isinstance(v, collections.MutableMapping):
column_names.extend(
get_column_names(v, column_name).items()
)
else:
column_names.append((column_name, v))
return dict(column_names)
def get_nested_value(d, key):
"""Return a dictionary item given a dictionary `d` and a flattened key from `get_column_names`.
Example:
d = {
'a': {
'b': 2,
'c': 3,
},
}
key = 'a.b'
will return: 2
"""
if '.' not in key:
if key not in d:
return None
return d[key]
base_key, sub_key = key.split('.', 1)
if base_key not in d:
return None
sub_dict = d[base_key]
return get_nested_value(sub_dict, sub_key)
def get_row(line_contents, column_names):
"""Return a csv compatible row given column names and a dict."""
row = []
for column_name in column_names:
line_value = get_nested_value(
line_contents,
column_name,
)
if isinstance(line_value, unicode):
row.append('{0}'.format(line_value.encode('utf-8')))
elif line_value is not None:
row.append('{0}'.format(line_value))
else:
row.append('')
return row
if __name__ == '__main__':
"""Convert a yelp dataset file from json to csv."""
parser = argparse.ArgumentParser(
description='Convert Yelp Dataset Challenge data from JSON format to CSV.',
)
parser.add_argument(
'json_file',
type=str,
help='The json file to convert.',
)
args = parser.parse_args()
json_file = args.json_file
csv_file = '{0}.csv'.format(json_file.split('.json')[0])
column_names = get_superset_of_column_names_from_file(json_file)
read_and_write_file(json_file, csv_file, column_names)
答案 3 :(得分:0)
执行:
OUTPUT = $(notdir $(lastword $(CURDIR)))
all $(OUTPUT):
g++ *.cpp -o $(OUTPUT)