summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--tools/fakedeps.nim18
-rw-r--r--tools/trimcc.nim207
2 files changed, 145 insertions, 80 deletions
diff --git a/tools/fakedeps.nim b/tools/fakedeps.nim
new file mode 100644
index 000000000..80623fafb
--- /dev/null
+++ b/tools/fakedeps.nim
@@ -0,0 +1,18 @@
+import strutils, os, pegs, strtabs, math, threadpool, times
+
+proc fakeCppDep(x: ptr float) {.importcpp: "fakeCppDep", header: "<vector>".}
+proc fakeTimeDep() = echo(times.getDateStr())
+proc fakedeps() =
+  var x = 0.4
+  {.emit: "#if 0\n".}
+  fakeCppDep(addr x)
+  {.emit: "#endif\n".}
+
+  # this is not true:
+  if math.sin(x) > 0.6:
+    spawn(fakeTimeDep())
+
+proc main =
+  fakedeps()
+when isMainModule:
+  main()
\ No newline at end of file
diff --git a/tools/trimcc.nim b/tools/trimcc.nim
index b6bf282b6..276ea1dbe 100644
--- a/tools/trimcc.nim
+++ b/tools/trimcc.nim
@@ -1,34 +1,17 @@
-# Trim C compiler installation to a minimum

-

-import strutils, os, pegs, strtabs, math, threadpool, times

+# Trim C compiler installation to a minimum
 
-proc fakeCppDep(x: ptr float) {.importcpp: "fakeCppDep", header: "<vector>".}
+import strutils, os, pegs, strtabs, math, threadpool, times
 
 const
   Essential = """gcc.exe g++.exe gdb.exe ld.exe as.exe c++.exe cpp.exe cc1.exe
-crtbegin.o crtend.o crt2.o dllcrt2.o
-libexpat-1.dll libwinpthread-1.dll
-
-aio.h
-dlfcn.h
-fcntl.h fenv.h fmtmsg.h fnmatch.h ftw.h
-errno.h
-glob.h gtmath.h
-if.h in.h ipc.h
-langinfo.h locale.h
-math.h mman.h
-netdb.h nl_types.h
-poll.h pthread.h pwd.h
-sched.h select.h semaphore.h signal.h
-socket.h spawn.h stat.h statvfs.h stdio.h stdlib.h string.h strings.h
-tcp.h time.h types.h
-ucontext.h uio.h utsname.h unistd.h
-wait.h
-varargs.h
-windows.h
-zlib.h
+crtbegin.o crtend.o crt2.o dllcrt2.o libgcc_s_dw2-1.dll libgcc_s_sjlj-1.dll
+libgcc_s_seh-1.dll libexpat-1.dll libwinpthread-1.dll aio.h dlfcn.h fcntl.h
+fenv.h fmtmsg.h fnmatch.h ftw.h errno.h glob.h gtmath.h if.h in.h ipc.h
+langinfo.h locale.h math.h mman.h netdb.h nl_types.h poll.h pthread.h pwd.h
+sched.h select.h semaphore.h signal.h socket.h spawn.h stat.h statvfs.h stdio.h
+stdlib.h string.h strings.h tcp.h time.h types.h ucontext.h uio.h utsname.h
+unistd.h wait.h varargs.h windows.h zlib.h
 """.split
-  BucketSize = 40
 
 proc includes(headerpath, headerfile: string, whitelist: StringTableRef) =
   whitelist[headerfile] = "processed"
@@ -40,88 +23,152 @@ proc includes(headerpath, headerfile: string, whitelist: StringTableRef) =
       if whitelist[m] != "processed":
         whitelist[m] = "found"
 
-proc processIncludes(dir: string, whitelist: StringTableRef) =

-  for kind, path in walkDir(dir):

-    case kind

+proc processIncludes(dir: string, whitelist: StringTableRef) =
+  for kind, path in walkDir(dir):
+    case kind
     of pcFile:
       let name = extractFilename(path)
       if ('.' notin name and "include" in path) or ("c++" in path):
         let n = whitelist[name]
-        if n != "processed": whitelist[name] = "found"

+        if n != "processed": whitelist[name] = "found"
       if name.endswith(".h"):
         let n = whitelist[name]
         if n == "found": includes(path, name, whitelist)
-    of pcDir: processIncludes(path, whitelist)

+    of pcDir: processIncludes(path, whitelist)
     else: discard
 
-proc gatherFiles(dir: string, whitelist: StringTableRef, result: var seq[string]) =

-  for kind, path in walkDir(dir):

-    case kind

+proc gatherFiles(dir: string, whitelist: StringTableRef, result: var seq[string]) =
+  for kind, path in walkDir(dir):
+    case kind
     of pcFile:
-      let name = extractFilename(path)

+      let name = extractFilename(path)
       if not whitelist.hasKey(name):
         result.add(path)
-    of pcDir: gatherFiles(path, whitelist, result)

-    else: discard

-

-proc newName(f: string): string =

-  let (dir, name, ext) = splitFile(f)

-  return dir / "trim_" & name & ext

+    of pcDir:
+      gatherFiles(path, whitelist, result)
+    else:
+      discard
+
+proc gatherEmptyFolders(dir: string, whitelist: StringTableRef, result: var seq[string]) =
+  var empty = true
+  for kind, path in walkDir(dir):
+    case kind
+    of pcFile:
+      empty = false
+    of pcDir:
+      let (none, name) = splitPath(path)
+      if not whitelist.hasKey(name):
+        gatherEmptyFolders(path, whitelist, result)
+      empty = false
+    else:
+      discard
+  if empty:
+    result.add(dir)
+
+proc newName(f: string): string =
+  let (dir, name, ext) = splitFile(f)
+  return dir / "trim_" & name & ext
 
 proc ccStillWorks(): bool =
   const
-    c1 = r"nim c --force_build koch"
-    c2 = r"nim c --force_build --threads:on --out:temp.exe tools/trimcc"
-  result = execShellCmd(c1) == 0 and execShellCmd(c2) == 0
-

-proc trialDeletion(files: seq[string], a, b: int) =
-  for i in a .. min(b, files.high):
-    let path = files[i]
-    moveFile(dest=newName(path), source=path)

+    c1 = r"nim c --verbosity:0 --force_build koch"
+    c2 = r"nim c --verbosity:0 --force_build --threads:on --out:tempOne.exe trimcc"
+    c3 = r"nim c --verbosity:0 --force_build --threads:on --out:tempTwo.exe fakeDeps"
+    c4 = r".\koch.exe"
+    c5 = r".\tempOne.exe"
+    c6 = r".\tempTwo.exe"
+  result = execShellCmd(c1) == 0 and execShellCmd(c2) == 0 and
+           execShellCmd(c3) == 0 and execShellCmd(c4) == 0 and
+           execShellCmd(c5) == 0 and execShellCmd(c6) == 0
+
+proc trialDeletion(files: seq[string], a, b: int, whitelist: StringTableRef): bool =
+  result = true
+  var single = (a == min(b, files.high))
+  for path in files[a .. min(b, files.high)]:
+    try:
+      moveFile(dest=newName(path), source=path)
+    except OSError:
+      return false
+
+  # Test if compilation still works, even with the moved files.
   if ccStillWorks():
-    for i in a .. min(b, files.high):
-      let path = files[i]
-      echo "Optional: ", path

-      removeFile(newName(path))
-  else:
    for i in a .. min(b, files.high):
-      let path = files[i]
-      echo "Required: ", path

-      # copy back:

-      moveFile(dest=path, source=newName(path))

+    for path in files[a .. min(b, files.high)]:
+      try:
+        removeFile(newName(path))
+        echo "Optional: ", path
+      except OSError:
+        echo "Warning, couldn't move ", path
+        moveFile(dest=path, source=newName(path))
+        return false
+  else:
+    for path in files[a .. min(b, files.high)]:
+      echo "Required: ", path
+      moveFile(dest=path, source=newName(path))
+      if single:
+        whitelist[path] = "found"
+      result = false
 
 proc main(dir: string) =
+  # Construct a whitelist of files to not remove
   var whitelist = newStringTable(modeCaseInsensitive)
   for e in Essential:
     whitelist[e] = "found"
   while true:
     let oldLen = whitelist.len
     processIncludes(dir, whitelist)
-    if oldLen == whitelist.len: break
-  var allFiles: seq[string] = @[]
-  gatherFiles(dir, whitelist, allFiles)
-  when true:
+    if oldLen == whitelist.len:
+      break
+
+  # Remove batches of files
+  var nearlyDone = false
+  while true:
+    # Gather files to test
+    var allFiles = newSeq[string]()
+    gatherFiles(dir, whitelist, allFiles)
+
+    # Determine the initial size of groups to check
+    var
+      maxBucketSize = len(allFiles)
+      bucketSize = 1
+
+    # Loop through the list of files, deleting batches
     var i = 0
     while i < allFiles.len:
-      trialDeletion(allFiles, i, i+BucketSize-1)
-      inc i, BucketSize
-  else:
-    for x in allFiles: echo x
+      var success = trialDeletion(allFiles, i, i+bucketSize-1, whitelist)
+      inc i, bucketSize
+
+      # If we aren't on the last pass, adjust the batch size based on success
+      if not nearlyDone:
+        if success:
+          bucketSize = min(bucketSize * 2, maxBucketSize)
+        else:
+          bucketSize = max(bucketSize div 2, 1)
+      echo "Bucket size is now ", bucketSize
 
-proc fakeTimeDep() = echo(times.getDateStr())
+    # After looping through all the files, check if we need to break.
+    if nearlyDone:
+      break
+    if bucketSize == 1:
+      nearlyDone = true
+
+  while true:
+    var
+      emptyFolders = newSeq[string]()
+      changed = false
 
-proc fakedeps() =
-  var x = 0.4
-  {.emit: "#if 0\n".}
-  fakeCppDep(addr x)
-  {.emit: "#endif\n".}
+    gatherEmptyFolders(dir, whitelist, emptyFolders)
+    for path in emptyFolders:
+      removeDir(path)
+      if not ccStillWorks():
+        createDir(path)
+        whitelist[path] = "found"
+      else:
+        changed = true
+    if not changed:
+      break
 
-  # this is not true:
-  if math.sin(x) > 0.6:
-    spawn(fakeTimeDep())
-

 if paramCount() == 1:
   doAssert ccStillWorks()
-  fakedeps()

-  main(paramStr(1))

-else:

-  quit "Usage: trimcc c_compiler_directory"

+  main(paramStr(1))
+else:
+  quit "Usage: trimcc c_compiler_directory", QuitSuccess