Skip to content

Instantly share code, notes, and snippets.

@Orangenhain
Created November 28, 2013 12:45
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save Orangenhain/7691314 to your computer and use it in GitHub Desktop.
Save Orangenhain/7691314 to your computer and use it in GitHub Desktop.
Script that takes a ObjC .m file and tries to find unused (or duplicate) import statements by commenting out each #import line in turn and seeing if the project still compiles. You will have to change BUILD_DIR & BUILD_CMD.
#!/usr/bin/env ruby -w
class String
def starts_with?(prefix)
prefix.respond_to?(:to_str) && self[0, prefix.length] == prefix
end
end
HEADER_REGEX = /^#import\s+["<](.*)[">]/
BUILD_DIR = File.expand_path("~/Code/project_xyz")
BUILD_CMD = 'xcodebuild -target "Project XYZ" -configuration "Debug" build > /tmp/import_minimizer-build.log 2>&1'
FILE_TO_MINIMIZE = ARGV.shift
unless File.readable?(FILE_TO_MINIMIZE)
puts "Usage: import_minimizer.rb FileToMinimize.m"
puts "\t file path must be relative to #{BUILD_DIR} (or an absolute path)"
exit 1
end
Dir.chdir(BUILD_DIR)
lines = open(FILE_TO_MINIMIZE, "r").each_line.to_a
line_no = 0
counter = 0
puts "testing #{FILE_TO_MINIMIZE}"
printf ". checking for duplicates"
seen_headers = []
while line_no < lines.length
line = lines[line_no]
line_no += 1
next unless line.starts_with? "#import "
header = line[HEADER_REGEX, 1]
if seen_headers.include?(header)
lines[line_no-1] = "// #{line.strip} // -- duplicate\n"
counter += 1
end
seen_headers << header
end
puts " - found: #{counter}"
line_no = 0
while line_no < lines.length
line = lines[line_no]
unless line.starts_with? "#import "
line_no += 1
next
end
orig_line = line
header = line[HEADER_REGEX, 1]
printf ". checking import: #{header}"
lines[line_no] = "// #{orig_line.strip} // -- not needed\n"
open(FILE_TO_MINIMIZE, "w+") { |f| f.write(lines.join) }
`#{BUILD_CMD}`
if ($?.exitstatus != 0)
lines[line_no] = orig_line
puts " - needed"
else
puts " - NOT needed"
counter += 1
end
line_no += 1
end
puts "\nFound #{counter} #import's that are not needed / duplicates"
open(FILE_TO_MINIMIZE, "w+") { |f| f.write(lines.join) }
@soniccat
Copy link

recommend to add ARGV.each do|file| to be able to use it this way
find . -name "*.[mh]" | xargs ruby ./import_minimizer.rb

@gbattiston
Copy link

Hi, I just have a question on how exactly to use this script, because I keep getting this error.

import_minimizer.rb:16:in readable?': no implicit conversion of nil into String (TypeError) from import_minimizer.rb:16:in

'

I changed BUILD_DIR & BUILD_CMD correctly but I can't get this to work.

Thanks!!

@gbattiston
Copy link

@soniccat I got it to work, but It only checks the first file with your way.

Is there a way to recursively search every folder and check every file?

@hendych
Copy link

hendych commented Nov 8, 2019

Managed to use this script recursively by doing this on bash

find . -name "*.[mh]" | while read -r dir; do ruby ./import_minimizer.rb "${dir}"; done

@SheldonWangRJT
Copy link

I dont think this script can remove useless import.
After i update the target and cmd directory, It is able to check duplicate but i manually added some useless import, it is not able to identify it.

@Eitot
Copy link

Eitot commented May 14, 2023

If you use Swift in your project, importing the Swift header (SWIFT_OBJC_INTERFACE_HEADER_NAME) also imports the Swift bridging header (SWIFT_OBJC_BRIDGING_HEADER). Removing an #import statement which is also included in the bridging header therefore leads to false-positive results, as the project still compiles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment