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, build.target ~ "-strip");
108             }
109         }
110         if (build.variantCleanup)
111         {
112             foreach (entry; build.variantCleanup.stripTarget)
113             {
114                 stripPath(toolchainDir ~ entry.substituteVars, build.target ~ "-strip");
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, build.target ~ "-strip");
127             stripPath(path2, build.target ~ "-strip");
128             stripPath(path3, build.target ~ "-strip");
129             stripPath(path4, build.target ~ "-strip");
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         stripPath(path, hostStrip, true, false);
168         stripPath(path2, hostStrip, true, false);
169     }
170     endBulletPoint();
171 }
172 
173 void stripPath(Path path, string stripProgram, bool stripExes = false, bool stripLibs = true)
174 {
175     yapFunc(stripProgram, " ", path);
176     if (!path.exists || !path.isDir)
177         return;
178 
179     foreach (entry; path.dirEntries(SpanMode.depth))
180     {
181         if (!entry.isFile)
182             continue;
183         if (stripLibs && (entry.extension == ".so" || entry.extension == ".dll"))
184         {
185             // Skip linker script files (libc.so)
186             if (!runCollectLog("file -b " ~ entry).canFind("ASCII"))
187             {
188                 tryRunCollectLog(stripProgram ~ " " ~ entry);
189             }
190         }
191         else if (stripExes && (entry.extension == ".exe"
192                 || runCollectLog("file -b " ~ entry).canFind("executable")))
193         {
194             tryRunCollectLog(stripProgram ~ " " ~ entry);
195         }
196     }
197 }