Skip to content

Instantly share code, notes, and snippets.

@ebraraktas
Last active January 4, 2021 10:19
Show Gist options
  • Save ebraraktas/0770c745c1cf5560397ffd412eebcea7 to your computer and use it in GitHub Desktop.
Save ebraraktas/0770c745c1cf5560397ffd412eebcea7 to your computer and use it in GitHub Desktop.
Copy C or C++ include header dependencies recursively
# Example command:
# python copy_headers.py --headers tensorflow/lite/model.h tensorflow/lite/interpreter.h \
# --destination MyAwesomeProject/include
# --include-dirs ../flatbuffers/include # Note that these are relative to --source-dir
# --source-dir ../tensorflow/
import argparse
import os
import subprocess
def get_structure(file, directories):
for directory in directories:
if file.startswith(directory):
structure = os.path.dirname(file[len(directory) + (not directory.endswith('/')):])
return structure
return os.path.dirname(file)
def copy(src, dst):
with open(src, 'rb') as sf, open(dst, 'wb') as df:
df.write(sf.read())
if __name__ == '__main__':
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description="Copy header dependencies recuresively")
parser.add_argument("--include-dirs", nargs="*",
help="Header include directories, relative to source-dir")
parser.add_argument("--headers", nargs="*", required=True,
help="Header paths whose dependencies will be copied, relative to source-dir")
parser.add_argument("--destination", help="destination directory to copy files", required=True)
parser.add_argument("--dry-run", help="Just log, don't copy", action='store_true')
parser.add_argument("--gcc-args", help="gcc args to be passed", default="--std=c++11")
parser.add_argument("--source-dir", help="gcc args to be passed", default=".")
args = parser.parse_args()
include_dirs = args.include_dirs if args.include_dirs else []
source_dir = args.source_dir
include_dirs.append('.')
include_args = []
for include_dir in include_dirs:
include_args += ["-I", include_dir]
headers = args.headers
destination = args.destination
dry_run = args.dry_run
copy_files = dict() # filepath => directory structure under include dir
for header in headers:
cmd = ["g++", args.gcc_args] + include_args + ["-MM", header]
p = subprocess.Popen(cmd, cwd=source_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
out = out.decode('utf8')
files = out[out.index(':') + 1:].replace('\\', '').split()
for file in files:
copy_files[os.path.abspath(os.path.join(source_dir, file))] = get_structure(file, include_dirs)
for file, file_dir in copy_files.items():
file_destination = os.path.join(destination, file_dir, os.path.basename(file))
if dry_run:
print(f'Would copy: {file} => {file_destination}')
else:
destination_dir = os.path.dirname(file_destination)
if not os.path.exists(destination_dir):
os.makedirs(destination_dir)
copy(file, file_destination)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment