Fix linking of DLL's on Windows

On Windows the runtime search path for DLL's is the same as PATH.
This patch changes the test suite to add the libc++ build directory
to the runtime PATH.

llvm-svn: 291309
This commit is contained in:
Eric Fiselier 2017-01-07 00:01:55 +00:00
parent d92e7f9f74
commit 93619335df
3 changed files with 63 additions and 23 deletions

View File

@ -67,7 +67,8 @@ class Configuration(object):
self.cxx_library_root = None
self.cxx_runtime_root = None
self.abi_library_root = None
self.env = {}
self.link_shared = self.get_lit_bool('enable_shared', default=True)
self.exec_env = {}
self.use_target = False
self.use_system_cxx_lib = False
self.use_clang_verify = False
@ -146,7 +147,7 @@ class Configuration(object):
# Print as list to prevent "set([...])" from being printed.
self.lit_config.note('Using available_features: %s' %
list(self.config.available_features))
self.lit_config.note('Using environment: %r' % self.env)
self.lit_config.note('Using environment: %r' % self.exec_env)
def get_test_format(self):
return LibcxxTestFormat(
@ -154,7 +155,7 @@ class Configuration(object):
self.use_clang_verify,
self.execute_external,
self.executor,
exec_env=self.env)
exec_env=self.exec_env)
def configure_executor(self):
exec_str = self.get_lit_conf('executor', "None")
@ -207,6 +208,11 @@ class Configuration(object):
self.config.available_features.add('%s-%s' % (cxx_type, maj_v))
self.config.available_features.add('%s-%s.%s' % (
cxx_type, maj_v, min_v))
self.cxx.compile_env = dict(os.environ)
# 'CCACHE_CPP2' prevents ccache from stripping comments while
# preprocessing. This is required to prevent stripping of '-verify'
# comments.
self.cxx.compile_env['CCACHE_CPP2'] = '1'
def _configure_clang_cl(self, clang_path):
assert self.cxx_is_clang_cl
@ -555,7 +561,7 @@ class Configuration(object):
if not os.path.isdir(dynamic_env):
os.makedirs(dynamic_env)
self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT="%s"' % dynamic_env]
self.env['LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT'] = ("%s" % dynamic_env)
self.exec_env['LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT'] = ("%s" % dynamic_env)
dynamic_helper = os.path.join(self.libcxx_src_root, 'test', 'support',
'filesystem_dynamic_test_helper.py')
@ -577,7 +583,7 @@ class Configuration(object):
self.cxx.link_flags += ['-nodefaultlibs']
# FIXME: Handle MSVCRT as part of the ABI library handling.
if self.is_windows:
self.cxx.link_flags += ['-nostdlib', '-lmsvcrtd']
self.cxx.link_flags += ['-nostdlib']
self.configure_link_flags_cxx_library()
self.configure_link_flags_abi_library()
self.configure_extra_library_flags()
@ -602,8 +608,14 @@ class Configuration(object):
if not self.use_system_cxx_lib:
if self.cxx_library_root:
self.cxx.link_flags += ['-L' + self.cxx_library_root]
if self.cxx_runtime_root and not self.is_windows:
self.cxx.link_flags += ['-Wl,-rpath,' + self.cxx_runtime_root]
if self.is_windows and self.link_shared:
self.add_path(self.cxx.compile_env, self.cxx_library_root)
if self.cxx_runtime_root:
if not self.is_windows:
self.cxx.link_flags += ['-Wl,-rpath,' +
self.cxx_runtime_root]
elif self.is_windows and self.link_shared:
self.add_path(self.exec_env, self.cxx_runtime_root)
def configure_link_flags_abi_library_path(self):
# Configure ABI library paths.
@ -612,14 +624,15 @@ class Configuration(object):
self.cxx.link_flags += ['-L' + self.abi_library_root]
if not self.is_windows:
self.cxx.link_flags += ['-Wl,-rpath,' + self.abi_library_root]
else:
self.add_path(self.exec_env, self.abi_library_root)
def configure_link_flags_cxx_library(self):
libcxx_experimental = self.get_lit_bool('enable_experimental', default=False)
if libcxx_experimental:
self.config.available_features.add('c++experimental')
self.cxx.link_flags += ['-lc++experimental']
libcxx_shared = self.get_lit_bool('enable_shared', default=True)
if libcxx_shared:
if self.link_shared:
self.cxx.link_flags += ['-lc++']
else:
cxx_library_root = self.get_lit_conf('cxx_library_root')
@ -654,7 +667,8 @@ class Configuration(object):
elif cxx_abi == 'libcxxrt':
self.cxx.link_flags += ['-lcxxrt']
elif cxx_abi == 'none' or cxx_abi == 'default':
pass
if self.is_windows:
self.cxx.link_flags += ['-lmsvcrtd']
else:
self.lit_config.fatal(
'C++ ABI setting %s unsupported for tests' % cxx_abi)
@ -746,7 +760,7 @@ class Configuration(object):
self.cxx.flags += ['-fsanitize=undefined',
'-fno-sanitize=vptr,function,float-divide-by-zero',
'-fno-sanitize-recover=all']
self.env['UBSAN_OPTIONS'] = 'print_stacktrace=1'
self.exec_env['UBSAN_OPTIONS'] = 'print_stacktrace=1'
self.config.available_features.add('ubsan')
# Setup the sanitizer compile flags
@ -754,10 +768,10 @@ class Configuration(object):
if san == 'Address' or san == 'Address;Undefined' or san == 'Undefined;Address':
self.cxx.flags += ['-fsanitize=address']
if llvm_symbolizer is not None:
self.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer
self.exec_env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer
# FIXME: Turn ODR violation back on after PR28391 is resolved
# https://llvm.org/bugs/show_bug.cgi?id=28391
self.env['ASAN_OPTIONS'] = 'detect_odr_violation=0'
self.exec_env['ASAN_OPTIONS'] = 'detect_odr_violation=0'
self.config.available_features.add('asan')
self.config.available_features.add('sanitizer-new-delete')
self.cxx.compile_flags += ['-O1']
@ -769,7 +783,7 @@ class Configuration(object):
self.cxx.compile_flags += [
'-fsanitize-memory-track-origins']
if llvm_symbolizer is not None:
self.env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer
self.exec_env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer
self.config.available_features.add('msan')
self.config.available_features.add('sanitizer-new-delete')
self.cxx.compile_flags += ['-O1']
@ -855,8 +869,8 @@ class Configuration(object):
sub.append(('%link', link_str))
sub.append(('%build', build_str))
# Configure exec prefix substitutions.
exec_env_str = 'env ' if len(self.env) != 0 else ''
for k, v in self.env.items():
exec_env_str = 'env ' if len(self.exec_env) != 0 else ''
for k, v in self.exec_env.items():
exec_env_str += ' %s=%s' % (k, v)
# Configure run env substitution.
exec_str = exec_env_str
@ -898,4 +912,12 @@ class Configuration(object):
"inferred target_triple as: %r" % self.config.target_triple)
def configure_env(self):
self.target_info.configure_env(self.env)
self.target_info.configure_env(self.exec_env)
def add_path(self, dest_env, new_path):
if 'PATH' not in dest_env:
dest_env['PATH'] = new_path
else:
split_char = ';' if self.is_windows else ':'
dest_env['PATH'] = '%s%s%s' % (new_path, split_char,
dest_env['PATH'])

View File

@ -7,6 +7,7 @@
#
#===----------------------------------------------------------------------===##
import platform
import os
from libcxx.test import tracing
@ -34,6 +35,7 @@ class Executor(object):
class LocalExecutor(Executor):
def __init__(self):
super(LocalExecutor, self).__init__()
self.is_windows = platform.system() == 'Windows'
def run(self, exe_path, cmd=None, work_dir='.', file_deps=None, env=None):
cmd = cmd or [exe_path]
@ -43,9 +45,30 @@ class LocalExecutor(Executor):
env_cmd += ['%s=%s' % (k, v) for k, v in env.items()]
if work_dir == '.':
work_dir = os.getcwd()
out, err, rc = executeCommand(env_cmd + cmd, cwd=work_dir)
if not self.is_windows:
out, err, rc = executeCommand(env_cmd + cmd, cwd=work_dir)
else:
out, err, rc = executeCommand(cmd, cwd=work_dir,
env=self._build_windows_env(env))
return (env_cmd + cmd, out, err, rc)
def _build_windows_env(self, exec_env):
# FIXME: Finding Windows DLL's at runtime requires modifying the
# PATH environment variables. However we don't want to print out
# the entire PATH as part of the diagnostic for every failing test.
# Therefore this hack builds a new executable environment that
# merges the current environment and the supplied environment while
# still only printing the supplied environment in diagnostics.
if not self.is_windows or exec_env is None:
return None
new_env = dict(os.environ)
for key, value in exec_env.items():
if key == 'PATH':
assert value.strip() != '' and "expected non-empty path"
new_env['PATH'] = "%s;%s" % (value, os.environ['PATH'])
else:
new_env[key] = value
return new_env
class PrefixExecutor(Executor):
"""Prefix an executor with some other command wrapper.

View File

@ -41,11 +41,6 @@ class LibcxxTestFormat(object):
self.execute_external = execute_external
self.executor = executor
self.exec_env = dict(exec_env)
self.cxx.compile_env = dict(os.environ)
# 'CCACHE_CPP2' prevents ccache from stripping comments while
# preprocessing. This is required to prevent stripping of '-verify'
# comments.
self.cxx.compile_env['CCACHE_CPP2'] = '1'
@staticmethod
def _make_custom_parsers():