1
# Python module containing general build functions
2
# for OpenVPN on Windows
4
import os, re, shutil, stat
6
autogen = "Automatically generated by OpenVPN Windows build system"
10
parse_version_m4(kv, home_fn('version.m4'))
11
parse_settings_in(kv, mod_fn('settings.in'))
14
kv['DDKVER'] = os.path.basename(kv['DDK_PATH'])
15
kv['DDKVER_MAJOR'] = re.match(r'^(\d+)\.', kv['DDKVER']).groups()[0]
17
if 'VERSION_SUFFIX' in kv:
18
kv['PRODUCT_VERSION'] += kv['VERSION_SUFFIX']
22
def mod_fn(fn, src=__file__, real=True):
23
p = os.path.join(os.path.dirname(src), os.path.normpath(fn))
25
p = os.path.realpath(p)
28
def home_fn(fn, real=True):
29
return mod_fn(os.path.join('..', fn), real=real)
32
os.chdir(os.path.join(os.path.dirname(__file__), '..'))
38
def parse_version_m4(kv, version_m4):
39
r = re.compile(r'^define\((\w+),\[(.*)\]\)$')
49
def parse_settings_in(kv, settings_in):
50
r = re.compile(r'^!define\s+(\w+)(?:\s+"?(.*?)"?)?$')
60
def dict_def(dict, newdefs):
65
def build_autodefs(kv, autodefs_in, autodefs_out):
71
head_comment='/* %s */\n\n' % autogen)
73
def preprocess(kv, in_fn, out_fn, quote_begin=None, quote_end=None, if_prefix=None, head_comment=None):
76
return kv.get(var, '')
78
re_macro = re_ifdef = None
80
if quote_begin and quote_end:
81
re_macro = re.compile(r'%s(\w+)%s' % (re.escape(quote_begin), re.escape(quote_end)))
84
re_ifdef = re.compile(r'^\s*%sifdef\s+(\w+)\b' % (re.escape(if_prefix),))
85
re_else = re.compile(r'^\s*%selse\b' % (re.escape(if_prefix),))
86
re_endif = re.compile(r'^\s*%sendif\b' % (re.escape(if_prefix),))
90
fout = open(out_fn, 'w')
92
fout.write(head_comment)
95
m = re.match(re_ifdef, line)
98
if_stack.append(int(var in kv))
100
elif re.match(re_else, line):
103
elif re.match(re_endif, line):
106
if not if_stack or min(if_stack):
108
line = re.sub(re_macro, repfn, line)
114
def print_key_values(kv):
115
for k, v in sorted(kv.items()):
116
print "%s%s%s" % (k, ' '*(32-len(k)), repr(v))
118
def get_sources(makefile_am):
121
f = open(makefile_am)
125
if line == 'openvpn_SOURCES = \\':
130
for sf in line.split():
131
if sf.endswith('.c'):
133
elif sf.endswith('.h'):
138
print >>sys.stderr, "Unrecognized filename:", sf
140
return [ sorted(list(s)) for s in (c, h) ]
142
def output_mak_list(title, srclist, ext):
143
ret = "%s =" % (title,)
145
ret += " \\\n\t%s.%s" % (x, ext)
149
def make_headers_objs(makefile_am):
150
c, h = get_sources(makefile_am)
151
ret = output_mak_list('HEADERS', h, 'h')
152
ret += output_mak_list('OBJS', c, 'obj')
155
def choose_arch(arch_name):
156
if arch_name == 'x64':
158
elif arch_name == 'x86':
160
elif arch_name == 'all':
163
raise ValueError("architecture ('%s') must be x86, x64, or all" % (arch_name,))
167
shutil.rmtree(dir, ignore_errors=True)
173
def cp_a(src, dest, dest_is_dir=True):
175
dest = os.path.join(dest, os.path.basename(src))
176
print "COPY_DIR %s %s" % (src, dest)
177
shutil.copytree(src, dest)
179
def cp(src, dest, dest_is_dir=True):
181
dest = os.path.join(dest, os.path.basename(src))
182
print "COPY %s %s" % (src, dest)
183
shutil.copyfile(src, dest)
187
shutil.rmtree(path, onerror=onerror)
191
def onerror(func, path, exc_info):
193
Error handler for ``shutil.rmtree``.
195
If the error is due to an access error (read only file)
196
it attempts to add write permission and then retries.
198
If the error is for another reason it re-raises the error.
200
Usage : ``shutil.rmtree(path, onerror=onerror)``
202
if not os.access(path, os.W_OK):
203
# Is the error an access error ?
204
os.chmod(path, stat.S_IWUSR)
209
def mkdir_silent(dir):
215
config = get_config()
1
# Python module containing general build functions
2
# for OpenVPN on Windows
4
import os, re, shutil, stat
6
autogen = "Automatically generated by OpenVPN Windows build system"
10
parse_version_m4(kv, home_fn('version.m4'))
11
parse_settings_in(kv, mod_fn('settings.in'))
14
kv['DDKVER'] = os.path.basename(kv['DDK_PATH'])
15
kv['DDKVER_MAJOR'] = re.match(r'^(\d+)\.', kv['DDKVER']).groups()[0]
17
if 'VERSION_SUFFIX' in kv:
18
kv['PRODUCT_VERSION'] += kv['VERSION_SUFFIX']
22
def get_build_params():
24
parse_build_params(kv,mod_fn('settings.in'))
28
def mod_fn(fn, src=__file__, real=True):
29
p = os.path.join(os.path.dirname(src), os.path.normpath(fn))
31
p = os.path.realpath(p)
34
def home_fn(fn, real=True):
35
return mod_fn(os.path.join('..', fn), real=real)
38
os.chdir(os.path.join(os.path.dirname(__file__), '..'))
40
def cd_service_win32():
41
os.chdir(os.path.join(os.path.dirname(__file__), '../service-win32'))
47
def run_in_vs_shell(cmd):
48
"""Make sure environment variables are setup before running command"""
49
os.environ['PATH'] += ";%s\\VC" % (os.path.normpath(config['MSVC']),)
50
system('cmd /c "vcvarsall.bat x86 && %s"' % (cmd,))
52
def parse_version_m4(kv, version_m4):
53
'''Parse define lines in version.m4'''
54
r = re.compile(r'^define\((\w+),\[(.*)\]\)$')
63
# If we encounter PRODUCT_TAP_WIN32_MIN_MAJOR or
64
# PRODUCT_TAP_WIN32_MIN_MAJOR then we need to generate extra
65
# variables, PRODUCT_TAP_MAJOR_VER and PRODUCT_TAP_MINOR_VER with
66
# the same contents. This is necessary because tap-win32/tapdrv.c
67
# build depends on those.
68
if g[0] == 'PRODUCT_TAP_WIN32_MIN_MAJOR':
69
kv['PRODUCT_TAP_MAJOR_VER'] = g[1]
70
elif g[0] == 'PRODUCT_TAP_WIN32_MIN_MINOR':
71
kv['PRODUCT_TAP_MINOR_VER'] = g[1]
73
# Add the variable to build configuration
77
def parse_settings_in(kv, settings_in):
78
r = re.compile(r'^!define\s+(\w+)(?:\s+"?(.*?)"?)?$')
88
def parse_build_params(kv, settings_in):
89
r = re.compile(r'^!define\s+(ENABLE_\w+)\s+(\w+)')
96
# Check if this is a #define line starts with ENABLE_
101
kv[g[0]] = g[1] or ''
104
def dict_def(dict, newdefs):
109
def build_autodefs(kv, autodefs_in, autodefs_out):
115
head_comment='/* %s */\n\n' % autogen)
117
def build_config_h(kv):
118
"""Generate static win/config.h to config.h to mimic autotools behavior"""
120
in_fn=mod_fn('config.h.in'),
121
out_fn=home_fn('config.h'),
124
head_comment='/* %s */\n\n' % autogen)
126
def build_configure_h(kv, configure_h_out, head_comment):
127
"""Generate a configure.h dynamically"""
128
fout = open(configure_h_out, 'w')
130
# These two variables are required to view build parameters during runtime
131
configure_defines='#define CONFIGURE_DEFINES \"'
132
configure_call='#define CONFIGURE_CALL \" config_all.py \"'
134
# Initialize the list of enabled features
138
fout.write(head_comment)
140
dict = get_build_params()
142
for key, value in dict.iteritems():
143
# Add enabled features
144
features = features + "#define " + key + " " + value + "\n"
146
# Add each enabled feature to CONFIGURE_DEFINES list
147
configure_defines = configure_defines + " " + key + "=" + value + ","
149
configure_defines = configure_defines + "\"" + "\n"
152
fout.write(configure_defines)
153
fout.write(configure_call)
158
def build_version_m4_vars(version_m4_vars_out, head_comment):
159
"""Generate a temporary file containing variables from version.m4 in
160
win/settings.in format. This done to allow importing them in win/openvpn.nsi"""
162
fout = open(version_m4_vars_out, 'w')
163
fout.write(head_comment)
166
parse_version_m4(kv, home_fn('version.m4'))
168
for key, value in kv.iteritems():
169
line = "!define " + key + "\t" + "\"" + value + "\"" + "\n"
174
def preprocess(kv, in_fn, out_fn, quote_begin=None, quote_end=None, if_prefix=None, head_comment=None):
177
return kv.get(var, '')
179
re_macro = re_ifdef = None
181
if quote_begin and quote_end:
182
re_macro = re.compile(r'%s(\w+)%s' % (re.escape(quote_begin), re.escape(quote_end)))
185
re_ifdef = re.compile(r'^\s*%sifdef\s+(\w+)\b' % (re.escape(if_prefix),))
186
re_else = re.compile(r'^\s*%selse\b' % (re.escape(if_prefix),))
187
re_endif = re.compile(r'^\s*%sendif\b' % (re.escape(if_prefix),))
191
fout = open(out_fn, 'w')
193
fout.write(head_comment)
196
m = re.match(re_ifdef, line)
199
if_stack.append(int(var in kv))
201
elif re.match(re_else, line):
204
elif re.match(re_endif, line):
207
if not if_stack or min(if_stack):
209
line = re.sub(re_macro, repfn, line)
215
def print_key_values(kv):
216
for k, v in sorted(kv.items()):
217
print "%s%s%s" % (k, ' '*(32-len(k)), repr(v))
219
def get_sources(makefile_am):
220
"""Parse ../Makefile.am to obtain a list of .h and .c files"""
223
f = open(makefile_am)
227
if line == 'openvpn_SOURCES = \\':
232
for sf in line.split():
233
if sf.endswith('.c'):
235
elif sf.endswith('.h'):
240
print >>sys.stderr, "Unrecognized filename:", sf
242
return [ sorted(list(s)) for s in (c, h) ]
244
def output_mak_list(title, srclist, ext):
245
ret = "%s =" % (title,)
247
ret += " \\\n\t%s.%s" % (x, ext)
251
def make_headers_objs(makefile_am):
252
"""Generate HEADER and OBJS entries dynamically from ../Makefile.am"""
253
c, h = get_sources(makefile_am)
254
ret = output_mak_list('HEADERS', h, 'h')
255
ret += output_mak_list('OBJS', c, 'obj')
258
def choose_arch(arch_name):
259
if arch_name == 'x64':
261
elif arch_name == 'x86':
263
elif arch_name == 'all':
266
raise ValueError("architecture ('%s') must be x86, x64, or all" % (arch_name,))
270
shutil.rmtree(dir, ignore_errors=True)
276
def cp_a(src, dest, dest_is_dir=True):
278
dest = os.path.join(dest, os.path.basename(src))
279
print "COPY_DIR %s %s" % (src, dest)
280
shutil.copytree(src, dest)
282
def cp(src, dest, dest_is_dir=True):
284
dest = os.path.join(dest, os.path.basename(src))
285
print "COPY %s %s" % (src, dest)
286
shutil.copyfile(src, dest)
288
def rename(src, dest):
289
print "RENAME %s %s" % (src, dest)
290
shutil.move(src, dest)
294
shutil.rmtree(path, onerror=onerror)
298
def onerror(func, path, exc_info):
300
Error handler for ``shutil.rmtree``.
302
If the error is due to an access error (read only file)
303
it attempts to add write permission and then retries.
305
If the error is for another reason it re-raises the error.
307
Usage : ``shutil.rmtree(path, onerror=onerror)``
309
if not os.access(path, os.W_OK):
310
# Is the error an access error ?
311
os.chmod(path, stat.S_IWUSR)
316
def mkdir_silent(dir):
322
config = get_config()