1 module gccbuild.cleanup;
2 
3 import scriptlike, gccbuild, painlessjson, std.json;
4 
5 void cleanupToolchain(Duration totalTime)
6 {
7     startSection("Finalizing toolchain");
8 
9     removeFolders();
10     stripTargetLibraries();
11     stripHostBinaries();
12 
13     if (build.cleanup.matchesBuildType && !build.cleanup.commands.empty)
14     {
15         writeBulletPoint("Executing custom cleanup commands");
16         auto oldCWD = pushCWD(toolchainDir);
17         runBuildCommands(build.cleanup.commands);
18         endBulletPoint();
19     }
20 
21     writeBulletPoint("Writing GCC information");
22     auto info = GCCInfo(build.target, build.host, build.multilibs);
23     auto json = info.toJSON();
24     writeFile(toolchainDir ~ "gcc_info.json", toJSON(&json, true));
25     endBulletPoint();
26 
27     endSectionLog();
28     writelnLog();
29     writelnLog("Total execution time: ", totalTime);
30     closeLog();
31 
32     writeBulletPoint("Compressing log file");
33     runCollectLog("xz -9 " ~ logFilePath.toString());
34     runCollectLog(
35         "mv " ~ (logFilePath.toString() ~ ".xz") ~ " " ~ (toolchainDir ~ "build.log.xz").toString());
36     endBulletPoint();
37 
38     endSection(false);
39 }
40 
41 struct GCCInfo
42 {
43     string target, host;
44     MultilibEntry[] multilibs;
45 }
46 
47 void removeFolders()
48 {
49     writeBulletPoint("Removing unnecessary folders");
50     if ((build.cleanup.matchesBuildType && !build.cleanup.remove.empty)
51             || (build.variantCleanup && !build.variantCleanup.remove.empty))
52     {
53         if (build.cleanup.matchesBuildType)
54         {
55             foreach (entry; build.cleanup.remove)
56             {
57                 tryRmdirRecurse(toolchainDir ~ entry.substituteVars);
58             }
59         }
60         if (build.variantCleanup)
61         {
62             foreach (entry; build.variantCleanup.remove)
63             {
64                 tryRmdirRecurse(toolchainDir ~ entry.substituteVars);
65             }
66         }
67     }
68     else
69     {
70         tryRmdirRecurse(sysrootDirWithPrefix ~ "bin");
71         tryRmdirRecurse(sysrootDirWithPrefix ~ "libexec");
72         tryRmdirRecurse(sysrootDirWithPrefix ~ "sbin");
73         tryRmdirRecurse(sysrootDirWithPrefix ~ "etc");
74         tryRmdirRecurse(sysrootDirWithPrefix ~ "var");
75         tryRmdirRecurse(sysrootDirWithPrefix ~ "share");
76         tryRmdirRecurse(sysrootDir ~ "bin");
77         tryRmdirRecurse(sysrootDir ~ "libexec");
78         tryRmdirRecurse(sysrootDir ~ "sbin");
79         tryRmdirRecurse(sysrootDir ~ "etc");
80         tryRmdirRecurse(sysrootDir ~ "var");
81         tryRmdirRecurse(sysrootDir ~ "share");
82         tryRmdirRecurse(toolchainDir ~ "etc");
83         tryRmdirRecurse(toolchainDir ~ "var");
84         tryRmdirRecurse(toolchainDir ~ "share");
85     }
86     endBulletPoint();
87 }
88 
89 void stripTargetLibraries()
90 {
91     if (skipStripLibraries)
92     {
93         writeBulletPoint("Stripping target libraries... (skipped)");
94         return;
95     }
96     writeBulletPoint("Stripping target libraries...");
97 
98     auto oldPath = updatePathVar(binDir);
99 
100     if ((build.cleanup.matchesBuildType && !build.cleanup.stripTarget.empty)
101             || (build.variantCleanup && !build.variantCleanup.stripTarget.empty))
102     {
103         if (build.cleanup.matchesBuildType)
104         {
105             foreach (entry; build.cleanup.stripTarget)
106             {
107                 stripPath(toolchainDir ~ entry.substituteVars, targetStrip);
108             }
109         }
110         if (build.variantCleanup)
111         {
112             foreach (entry; build.variantCleanup.stripTarget)
113             {
114                 stripPath(toolchainDir ~ entry.substituteVars, targetStrip);
115             }
116         }
117     }
118     else
119     {
120         foreach (multilib; build.multilibs)
121         {
122             auto path = sysrootDirWithPrefix ~ Path("lib") ~ Path(multilib.osFolder);
123             auto path2 = toolchainDir ~ Path(build.target) ~ Path("lib") ~ Path(multilib.osFolder);
124             auto path3 = toolchainDir ~ Path("lib") ~ Path(multilib.osFolder);
125             auto path4 = toolchainDir ~ Path("lib");
126             stripPath(path, targetStrip);
127             stripPath(path2, targetStrip);
128             stripPath(path3, targetStrip);
129             stripPath(path4, targetStrip);
130         }
131     }
132     restorePathVar(oldPath);
133     endBulletPoint();
134 }
135 
136 void stripHostBinaries()
137 {
138     if (skipStripBinaries)
139     {
140         writeBulletPoint("Stripping host binaries... (skipped)");
141         return;
142     }
143     writeBulletPoint("Stripping host binaries...");
144 
145     if ((build.cleanup.matchesBuildType && !build.cleanup.stripHost.empty)
146             || (build.variantCleanup && !build.variantCleanup.stripHost.empty))
147     {
148         if (build.cleanup.matchesBuildType)
149         {
150             foreach (entry; build.cleanup.stripHost)
151             {
152                 stripPath(toolchainDir ~ entry.substituteVars, hostStrip, true, false);
153             }
154         }
155         if (build.variantCleanup)
156         {
157             foreach (entry; build.variantCleanup.stripHost)
158             {
159                 stripPath(toolchainDir ~ entry.substituteVars, hostStrip, true, false);
160             }
161         }
162     }
163     else
164     {
165         auto path = toolchainDir ~ "bin";
166         auto path2 = toolchainDir ~ Path(build.target) ~ "bin";
167         auto path3 = toolchainDir ~ "libexec";
168         auto path4 = toolchainDir ~ Path(build.target) ~ "libexec";
169         stripPath(path, hostStrip, true, false);
170         stripPath(path2, hostStrip, true, false);
171         stripPath(path3, hostStrip, true, true);
172         stripPath(path4, hostStrip, true, true);
173     }
174     endBulletPoint();
175 }
176 
177 void stripPath(Path path, string stripProgram, bool stripExes = false, bool stripLibs = true)
178 {
179     yapFunc(stripProgram, " ", path);
180     if (!path.exists || !path.isDir)
181         return;
182 
183     foreach (entry; path.dirEntries(SpanMode.depth))
184     {
185         if (!entry.isFile)
186             continue;
187         if (stripLibs && (entry.extension == ".so" || entry.extension == ".dll"
188             || entry.extension == ".a" || entry.extension == ".lib"))
189         {
190             // Skip linker script files (libc.so)
191             if (!runCollectLog("file -b " ~ entry).canFind("ASCII"))
192             {
193                 tryRunCollectLog(stripProgram ~ " --strip-debug " ~ entry);
194             }
195         }
196         else if (stripExes && (entry.extension == ".exe"
197                 || runCollectLog("file -b " ~ entry).canFind("executable")))
198         {
199             tryRunCollectLog(stripProgram ~ " --strip-debug " ~ entry);
200         }
201     }
202 }