1#!/usr/bin/python3 2import os 3import sys 4import fnmatch 5 6 7__doc__ = """Build configurator for FLIF. 8 9Usage: 10 configure.py [options] [-D var]... 11 12Options: 13 --native Enable native optimizations. 14 -d, --debug Compile with debug. 15 -D var Define variable. Also -D EXAMPLE=1. 16 -o file Output ninja file [default: build.ninja]. 17 -h, --help Show this screen. 18""" 19 20def find_objects(n, dirpaths): 21 objects = [] 22 for dirpath in dirpaths: 23 for root, dirnames, filenames in os.walk(dirpath): 24 for filename in fnmatch.filter(filenames, "*.cpp"): 25 if "flif-interface" in filename: 26 continue 27 src = os.path.join(root, filename) 28 obj = os.path.join("obj", os.path.splitext(src)[0] + ".o") 29 n.build(obj, "cxx", src) 30 objects.append(obj) 31 return objects 32 33def write_ninja(n, args): 34 ######################## 35 # Generic build rules. # 36 ######################## 37 exe_ext = ".exe" if os.name == "nt" else "" 38 n.variable("cxx", "g++") 39 40 if args["--debug"]: 41 n.variable("dbgflags", "-ggdb") 42 debug_flag = "" 43 else: 44 n.variable("dbgflags", "") 45 debug_flag = " -DNDEBUG" 46 47 native_flag = " -march=native" if args["--native"] else "" 48 n.variable("optflags", "-O2 -ftree-vectorize" + native_flag + debug_flag) 49 50 defines = [" -D" + d for d in args["-D"]] 51 cxxflags = "-std=c++11 -Wall -pedantic `pkg-config --cflags zlib libpng`" 52 n.variable("cxxflags", cxxflags + "".join(defines)) 53 n.variable("cxxlinkflags", "`pkg-config --libs libpng`") 54 55 n.rule("cxx", 56 "$cxx $xtype -MMD -MF $out.d $optflags $dbgflags $cxxflags -c $in -o $out", 57 depfile="$out.d") 58 59 n.rule("cxxlink", "$cxx $optflags $dbgflags $in $cxxlinkflags -o $out") 60 61 ################### 62 # Build commands. # 63 ################### 64 objects = find_objects(n, ["extern", "src"]) 65 n.build("src/flif" + exe_ext, "cxxlink", objects) 66 n.default("src/flif" + exe_ext) 67 68 69try: 70 from docopt import docopt 71 import ninja_syntax 72except ImportError: 73 msg = """You are missing one or more dependencies, install using: 74 75 {} -m pip install --user docopt ninja-syntax 76 77If you are using an old version of Python, and don't have pip, 78download https://bootstrap.pypa.io/get-pip.py and run it.""" 79 80 print(msg.format(os.path.basename(sys.executable))) 81 sys.exit(1) 82 83 84args = docopt(__doc__) 85 86# Check if we're likely running for the first time. 87first_time = not os.path.isfile(args["-o"]) 88 89# Write ninja build file. 90with open(args["-o"], "w") as ninja_file: 91 n = ninja_syntax.Writer(ninja_file) 92 write_ninja(n, args) 93 94# Check if we have ninja in path. 95path = os.environ.get("PATH", os.defpath).split(os.pathsep) 96if sys.platform == "win32": 97 path.insert(0, os.curdir) 98 pathext = os.environ.get("PATHEXT", "").split(os.pathsep) 99 files = ["ninja" + ext for ext in pathext] 100else: 101 files = ["ninja"] 102 103is_exe = lambda p: os.path.exists(p) and os.access(p, os.F_OK | os.X_OK) and not os.path.isdir(p) 104has_ninja = any(is_exe(os.path.join(d, f)) for d in path for f in files) 105 106if first_time: 107 if not has_ninja: 108 msg = """It appears you're running configure.py for the first time, but do not have 109ninja in your path. On Windows we recommend simply downloading the binary: 110 111 https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip 112 113Extract anywhere in your path, or even inside this directory. 114 115On linux it's easiest to compile from source: 116 117 wget https://github.com/ninja-build/ninja/archive/v1.6.0.tar.gz 118 tar xf v1.6.0.tar.gz && rm v1.6.0.tar.gz && cd ninja-1.6.0 119 {} configure.py --bootstrap 120 sudo cp ninja /usr/local/bin 121 122This should only take half a minute or so.""" 123 print(msg.format(os.path.basename(sys.executable))) 124 else: 125 print("Type 'ninja' to build FLIF.") 126