-
Notifications
You must be signed in to change notification settings - Fork 10
/
cmake-atlas.py
224 lines (165 loc) · 7.05 KB
/
cmake-atlas.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
import sys
from pathlib import Path
DOUBLE_PRECISION = 0
# kaldi root
kaldi_root = 'your-kaldi-root-path'
# variables to openfst (change them to your path in kaldi.mk)
OPENFSTINC = 'your OPENFSTINC defined in kaldi.mk'
OPENFSTLIBS = 'your OPENFSTLIBS *so* in kaldi.mk'
# variables to atlas (change them to your path in kaldi.mk)
ATLASINC = 'your ATLASINC defined in kaldi.mk'
ATLASLIBS = 'your ATLASLIBS *so* in kaldi.mk'
dependency_libs = (OPENFSTLIBS +' ' + ATLASLIBS).split()
def generate_cmake(makefile_path, cmake_path):
"""
This is to parse Makefile under each subdirectory to generate corresponding CMakeLists.txt
:param makefile_path: path to Makefile
:param cmake_path: path to CMakeLists.txt
:return:
"""
makefile = open(str(makefile_path), 'r')
cmake = open(cmake_path, 'w')
print("Converting ", makefile_path, " --> ", cmake_path)
##############################################################################
# Step 1: Parsing Makefile
#
# This step is to parse makefile into libname, bin_files and obj_files
# each of them are corresponding to the library name, executable/test binary,
# object file respectively
##############################################################################
bin_files = []
obj_files = []
libname = None
# this is to enable atlas and openfst dependency
addlibs = [lib for lib in dependency_libs]
# this is to enable pthread flags
addlibs.append("${CMAKE_THREAD_LIBS_INIT}")
# denote current mode: bin, obj, libname or addlibs
mode = "mode"
# if current line finish with \, then next line will continue to use the same mode
mode_continous = False
# parse contents in makefile
for line in makefile:
line = line.strip()
# skip comments
if line.startswith("#"):
continue
else:
line = line.split('#')[0]
elems = []
if mode_continous:
elems = line.split()
# check whether the mode is continuing
if elems[-1] != '\\':
mode_continous = False
else:
# decide which mode is now and split line into elems
if line.startswith("TESTFILES") or line.startswith("BINFILES"):
mode = "bin"
elems = line.split()[2:]
elif line.startswith("OBJFILES"):
# delete .o extension
mode = "obj"
elems = line.split()[2:]
elif line.startswith("LIBNAME"):
mode = "libname"
elems = line.split()[2:]
elif line.startswith("ADDLIBS"):
mode = "addlibs"
elems = line.split()[2:]
else:
mode = "None"
elems = line.split()
# no essential component in this line
if len(elems) == 0 or mode == "None":
continue
# remove the new line symbol if necessary
if elems[-1] == '\\':
elems = elems[:-1]
mode_continous = True
# remove empty fields after split
# update for each mode
if mode == "bin":
bin_files.extend(elems)
elif mode == 'obj':
# delete .o extension and ignore cu-kernels.cu / chain-kernels.cu
obj_files.extend([obj[:-2] for obj in elems if len(obj) > 2 and obj != 'cu-kernels.o' and obj != 'chain-kernels.o'])
elif mode == 'libname':
assert len(elems) == 1
libname = elems[0]
elif mode == 'addlibs':
# clean paths
for relative_path in elems:
path = Path(relative_path)
addlibs.append(path.stem)
# clear current mode
if not mode_continous:
mode = "None"
# debug
print("libname: ", libname)
print("addlibs: ", addlibs)
print("bin: ", bin_files)
print("obj : ", obj_files)
##############################################################################
# Step 2: CMakeLists.txt generation
#
# Makefile parsing done
# start generate CMakeLists.txt here with roughly following rules:
#
# - libname, obj_files -> add_library
# - addlibs -> target_link_libraries
# - bin_files -> add_executable
##############################################################################
# ensure all bins are generated under the same directory
# this is to keep compatibility with original kaldi project
cmake.write('set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_SOURCE_DIR}")\n\n')
# generate library rules if libname is provided
if libname:
cmake.write('add_library('+libname+' '+'.cc '.join(obj_files)+'.cc)\n\n')
for addlib in addlibs:
cmake.write("target_link_libraries("+libname+" "+addlib+")\n")
# generate bins rules
parent_name = makefile_path.parent.name
for bin_file in bin_files:
# three nnet are conflicting, add parent name to prefix to prevent this issue
if bin_file.startswith("nnet"):
exe_file = parent_name +'-' + bin_file
else:
exe_file = bin_file
cmake.write("add_executable("+exe_file+" "+bin_file+".cc)\n")
# link libname if exists
if libname:
cmake.write("target_link_libraries("+exe_file+" "+libname+")\n")
else:
# link external libraries
for addlib in addlibs:
cmake.write("target_link_libraries("+exe_file+" "+addlib+")\n")
print("-"*80)
cmake.close()
if __name__ == '__main__':
src_dir = Path(kaldi_root) / 'src'
# directories we do not want to generate CMakeLists.txt
exclude_dirs = set(["doc", "gst-plugin", "makefiles", ".git", "probe", "tfrnnlm", "tfrnnlmbin", "online", "onlinebin", "cudadecoder", "cudadecoderbin", "cudafeat", "cudafeatbin", "cudamatrix"])
kaldi_cmake = open(kaldi_root + '/CMakeLists.txt', 'w')
# write project header
kaldi_cmake.write("cmake_minimum_required (VERSION 2.8)\n\nproject (kaldi)\n\n\ninclude_directories(src)\n\n")
# write kaldi flags
kaldi_cmake.write("find_package( Threads )\n")
kaldi_cmake.write("add_compile_definitions(HAVE_CXXABI_H)\n")
kaldi_cmake.write("add_compile_definitions(HAVE_EXECINFO_H=1)\n")
kaldi_cmake.write("add_compile_definitions(KALDI_DOUBLEPRECISION=0)\n")
kaldi_cmake.write("set (CMAKE_CXX_STANDARD 11)\n")
# write cmake dependency to atlas
kaldi_cmake.write("add_compile_definitions(HAVE_ATLAS)\n\ninclude_directories("+ATLASINC+")\n\n")
kaldi_cmake.write("include_directories("+OPENFSTINC+")\n\n")
# process subdirectory to generate cmakelists.txt iteratively
for sub_dir in src_dir.iterdir():
# skip execluded dirs
if str(sub_dir.name) in exclude_dirs:
continue
makefile_path = sub_dir / 'Makefile'
cmake_path = sub_dir / 'CMakeLists.txt'
if makefile_path.exists():
generate_cmake(makefile_path, cmake_path)
kaldi_cmake.write("add_subdirectory("+str(sub_dir)+")\n")
kaldi_cmake.close()