aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-02-24 20:31:11 -0800
committerAlon Zakai <alonzakai@gmail.com>2012-02-24 20:31:11 -0800
commitf5d4f09244b6041b6b93076f909b1671e2a38eae (patch)
tree230ed3bf320217508198e6a80444f0e43e3b1336
parent508e953fd41b09dba6c97033157caae2bfa3d5e4 (diff)
--ignore-dynamic-linking option in emcc
-rwxr-xr-xemcc29
-rwxr-xr-xtests/runner.py56
2 files changed, 78 insertions, 7 deletions
diff --git a/emcc b/emcc
index 249ba398..461a12d7 100755
--- a/emcc
+++ b/emcc
@@ -100,7 +100,7 @@ AUTODEBUG = os.environ.get('EMCC_AUTODEBUG') # If set to 1, we will run the auto
# Note that this will disable inclusion of libraries. This is useful because including
# dlmalloc makes it hard to compare native and js builds
-if DEBUG: print >> sys.stderr, 'emcc: ', ' '.join(sys.argv)
+if DEBUG: print >> sys.stderr, '\nemcc invocation: ', ' '.join(sys.argv)
if DEBUG and LEAVE_INPUTS_RAW: print >> sys.stderr, 'emcc: leaving inputs raw'
stdout = PIPE if not DEBUG else None # suppress output of child processes
@@ -186,6 +186,14 @@ Options that are modified or new in %s include:
to access the file in the current directory
with the same basename as given here (that is,
just the filename, without a path to it).
+ --ignore-dynamic-linking Normally emcc will treat dynamic linking like
+ static linking, by linking in the code from
+ the dynamic library. This fails if the same
+ dynamic library is linked more than once.
+ With this option, dynamic linking is ignored,
+ which allows the build system to proceed without
+ errors. However, you will need to manually
+ link to the shared libraries later on yourself.
--shell-file <path> The path name to a skeleton HTML file used
when generating HTML output. The shell file
used needs to have this token inside it:
@@ -245,7 +253,7 @@ if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += EMMAKEN_CFLAGS.split(' ')
SOURCE_SUFFIXES = ('.c', '.cpp', '.cxx', '.cc')
BITCODE_SUFFIXES = ('.bc', '.o')
-SHAREDLIB_SUFFIXES = ('.dylib', '.so', '.dll')
+DYNAMICLIB_SUFFIXES = ('.dylib', '.so', '.dll')
STATICLIB_SUFFIXES = ('.a',)
ASSEMBLY_SUFFIXES = ('.ll',)
LIB_PREFIXES = ('', 'lib')
@@ -317,6 +325,7 @@ try:
js_transform = None
compress_whitespace = None
embed_files = []
+ ignore_dynamic_linking = False
shell_path = shared.path_from_root('src', 'shell.html')
def check_bad_eq(arg):
@@ -361,6 +370,9 @@ try:
f.close()
newargs[i] = ''
newargs[i+1] = ''
+ elif newargs[i] == '--ignore-dynamic-linking':
+ ignore_dynamic_linking = True
+ newargs[i] = ''
elif newargs[i].startswith('--shell-file'):
check_bad_eq(newargs[i])
shell_path = newargs[i+1]
@@ -398,7 +410,7 @@ try:
for i in range(len(newargs)): # find input files XXX this a simple heuristic. we should really analyze based on a full understanding of gcc params,
# right now we just assume that what is left contains no more |-x OPT| things
arg = newargs[i]
- if arg.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + SHAREDLIB_SUFFIXES + ASSEMBLY_SUFFIXES) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs
+ if arg.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs
newargs[i] = ''
if os.path.exists(arg):
if arg.endswith(SOURCE_SUFFIXES):
@@ -425,8 +437,8 @@ try:
if DEBUG: print >> sys.stderr, 'emcc: looking for library "%s"' % lib
found = False
for prefix in LIB_PREFIXES:
- for suffix in STATICLIB_SUFFIXES + SHAREDLIB_SUFFIXES:
- name = prefix + lib + suffix
+ for suff in STATICLIB_SUFFIXES + DYNAMICLIB_SUFFIXES:
+ name = prefix + lib + suff
for lib_dir in lib_dirs:
path = os.path.join(lib_dir, name)
if os.path.exists(path):
@@ -437,6 +449,9 @@ try:
if found: break
if found: break
+ if ignore_dynamic_linking:
+ input_files = filter(lambda input_file: not input_file.endswith(DYNAMICLIB_SUFFIXES), input_files)
+
assert len(input_files) > 0, 'emcc: no input files'
newargs += CC_ADDITIONAL_ARGS
@@ -489,7 +504,7 @@ try:
temp_file = in_temp(unsuffixed_basename(input_file) + '.o')
shutil.copyfile(input_file, temp_file)
temp_files.append(temp_file)
- elif input_file.endswith(SHAREDLIB_SUFFIXES) or shared.Building.is_ar(input_file):
+ elif input_file.endswith(DYNAMICLIB_SUFFIXES) or shared.Building.is_ar(input_file):
if DEBUG: print >> sys.stderr, 'emcc: copying library file: ', input_file
temp_file = in_temp(os.path.basename(input_file))
shutil.copyfile(input_file, temp_file)
@@ -611,7 +626,7 @@ try:
# First, combine the bitcode files if there are several. We must also link if we have a singleton .a
if len(input_files) + len(extra_files_to_link) > 1 or \
- (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_SUFFIXES or suffix(temp_files[0]) in SHAREDLIB_SUFFIXES) and shared.Building.is_ar(temp_files[0])):
+ (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_SUFFIXES or suffix(temp_files[0]) in DYNAMICLIB_SUFFIXES) and shared.Building.is_ar(temp_files[0])):
linker_inputs = temp_files + extra_files_to_link
if DEBUG: print >> sys.stderr, 'emcc: linking: ', linker_inputs
shared.Building.link(linker_inputs,
diff --git a/tests/runner.py b/tests/runner.py
index 7dde21d7..814dd182 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -6168,6 +6168,62 @@ f.close()
Popen([EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--embed-file', 'somefile.txt']).communicate()
self.assertContained('|hello from a file wi|', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ def test_emcc_multidynamic_link(self):
+ # Linking the same dynamic library in will error, normally, since we statically link it, causing dupe symbols
+ # A workaround is to use --ignore-dynamic-linking, see emcc --help for details
+
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ extern void printey();
+ extern void printother();
+ int main() {
+ printf("*");
+ printey();
+ printf("\n");
+ printother();
+ printf("\n");
+ printf("*");
+ return 0;
+ }
+ ''')
+
+ try:
+ os.makedirs(os.path.join(self.get_dir(), 'libdir'));
+ except:
+ pass
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write('''
+ #include <stdio.h>
+ void printey() {
+ printf("hello from lib");
+ }
+ ''')
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), 'w').write('''
+ #include <stdio.h>
+ extern void printey();
+ void printother() {
+ printf("|");
+ printey();
+ printf("|");
+ }
+ ''')
+
+ # This lets us link the same dynamic lib twice. We will need to link it in manually at the end.
+ compiler = [EMCC, '--ignore-dynamic-linking']
+
+ # Build libfile normally into an .so
+ Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-o', os.path.join(self.get_dir(), 'libdir', 'libfile.so')]).communicate()
+ # Build libother and dynamically link it to libfile - but add --ignore-dynamic-linking
+ Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-o', os.path.join(self.get_dir(), 'libdir', 'libother.so')]).communicate()
+ # Build the main file, linking in both the libs
+ Popen(compiler + [os.path.join(self.get_dir(), 'main.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother', '-c']).communicate()
+
+ # The normal build system is over. We need to do an additional step to link in the dynamic libraries, since we ignored them before
+ Popen([EMCC, os.path.join(self.get_dir(), 'main.o'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother']).communicate()
+
+ self.assertContained('*hello from lib\n|hello from lib|\n*', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
def test_eliminator(self):
input = open(path_from_root('tools', 'eliminator', 'eliminator-test.js')).read()
expected = open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read()