3 # Generate a custom linker script/map file for the --enabled-mergedlibs merged library
4 # which reduces the startup time and enables further optimisations with --enable-lto because 60% or more
5 # of the symbols become internal only.
10 import multiprocessing
12 exported_symbols
= set()
13 imported_symbols
= set()
16 # look for symbols exported by libmerged
17 subprocess_nm
= subprocess
.Popen("nm -D instdir/program/libmergedlo.so", stdout
=subprocess
.PIPE
, shell
=True)
18 with subprocess_nm
.stdout
as txt
:
19 # We are looking for lines something like:
20 # 0000000000036ed0 T flash_component_getFactory
21 line_regex
= re
.compile(r
'^[0-9a-fA-F]+ T ')
23 line
= line
.strip().decode("utf-8")
24 if line_regex
.match(line
):
25 exported_symbols
.add(line
.split(" ")[2])
26 subprocess_nm
.terminate()
28 # look for symbols imported from libmerged
29 subprocess_find
= subprocess
.Popen("(find instdir/program/ -type f; ls ./workdir/LinkTarget/CppunitTest/*.so) | xargs grep -l mergedlo",
30 stdout
=subprocess
.PIPE
, shell
=True)
31 with subprocess_find
.stdout
as txt
:
33 sharedlib
= line
.strip().decode("utf-8")
34 s
= sharedlib
[sharedlib
.find("/lib") + 4 : len(sharedlib
) - 3]
35 # look for imported symbols
36 subprocess_objdump
= subprocess
.Popen("objdump -T " + sharedlib
, stdout
=subprocess
.PIPE
, shell
=True)
37 with subprocess_objdump
.stdout
as txt2
:
38 # ignore some header bumpf
43 # We are looking for lines something like (noting that one of them uses spaces, and the other tabs)
44 # 0000000000000000 DF *UND* 0000000000000000 _ZN16FilterConfigItem10WriteInt32ERKN3rtl8OUStringEi
46 line2
= line2
.strip().decode("utf-8")
47 if line2
.find("*UND*") == -1: continue
48 tokens
= line2
.split(" ")
49 sym
= tokens
[len(tokens
)-1].strip()
50 imported_symbols
.add(sym
)
51 subprocess_objdump
.terminate()
52 subprocess_find
.terminate()
54 intersec_symbols
= exported_symbols
.intersection(imported_symbols
)
55 print("no symbols exported from libmerged = " + str(len(exported_symbols
)))
56 print("no symbols that can be made internal = " + str(len(intersec_symbols
)))
58 # Now look for classes where none of the class symbols are imported,
59 # i.e. we can mark the whole class as hidden
61 def extract_class(sym
):
62 filtered_sym
= subprocess
.check_output(["c++filt", sym
]).strip().decode("utf-8")
63 if filtered_sym
.startswith("vtable for "):
64 classname
= filtered_sym
[11:]
66 if filtered_sym
.startswith("non-virtual thunk to "):
67 filtered_sym
= filtered_sym
[21:]
68 elif filtered_sym
.startswith("virtual thunk to "):
69 filtered_sym
= filtered_sym
[17:]
70 i
= filtered_sym
.find("(")
72 i
= filtered_sym
.rfind("::", 0, i
)
74 classname
= filtered_sym
[:i
]
78 pool
= multiprocessing
.Pool(multiprocessing
.cpu_count())
79 classes_with_exported_symbols
= set(pool
.map(extract_class
, list(exported_symbols
)))
80 classes_with_imported_symbols
= set(pool
.map(extract_class
, list(imported_symbols
)))
82 # Some stuff is particular to Windows, so won't be found by a Linux analysis, so remove
84 can_be_private_classes
= classes_with_exported_symbols
- classes_with_imported_symbols
;
85 can_be_private_classes
.discard("SpinField")
87 with
open("bin/find-mergedlib-can-be-private.classes.results", "wt") as f
:
88 for sym
in sorted(can_be_private_classes
):
89 if sym
.startswith("std::") or sym
.startswith("void std::"): continue