From 2e04a31c186d1739836bdcc302fe6ae1200cd74f Mon Sep 17 00:00:00 2001
From: Campbell Barton <ideasman42@gmail.com>
Date: Thu, 6 Mar 2014 22:50:06 +1100
Subject: [PATCH] Add assembler preview

---
 .../externaltools/qtc_assembler_preview.py    | 157 ++++++++++++++++++
 .../externaltools/qtc_assembler_preview.xml   |  11 ++
 2 files changed, 168 insertions(+)
 create mode 100755 utils_ide/qtcreator/externaltools/qtc_assembler_preview.py
 create mode 100644 utils_ide/qtcreator/externaltools/qtc_assembler_preview.xml

diff --git a/utils_ide/qtcreator/externaltools/qtc_assembler_preview.py b/utils_ide/qtcreator/externaltools/qtc_assembler_preview.py
new file mode 100755
index 0000000..2333251
--- /dev/null
+++ b/utils_ide/qtcreator/externaltools/qtc_assembler_preview.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python3
+
+"""
+Takes 2 args
+
+ qtc_assembler_preview.py <build_dir> <file.c/c++>
+
+Currently GCC is assumed
+"""
+
+
+import sys
+import os
+import shlex
+import subprocess
+
+BUILD_DIR = sys.argv[-2]
+SOURCE_FILE = sys.argv[-1]
+
+# TODO, support other compilers
+COMPILER_ID = 'GCC'
+
+def find_arg(source, data):
+    source_base = os.path.basename(source)
+    for l in data:
+        # chances are high that we found the file
+        if source_base in l:
+            # check if this file is in the line
+            l_split = shlex.split(l)
+            for w in l_split:
+                if w.endswith(source_base):
+                    if os.path.isabs(w):
+                        if os.path.samefile(w, source):
+                            # print(l)
+                            return l
+                    else:
+                        # check trailing path (a/b/c/d/e.c == d/e.c)
+                        w_sep = os.path.normpath(w).split(os.sep)
+                        s_sep = os.path.normpath(source).split(os.sep)
+                        m = min(len(w_sep), len(s_sep))
+                        if w_sep[-m:] == s_sep[-m:]:
+                            # print(l)
+                            return l
+
+
+def find_build_args_ninja(source):
+    make_exe = "ninja"
+    process = subprocess.Popen([make_exe, "-t", "commands"],
+                                stdout=subprocess.PIPE,
+                               )
+    while process.poll():
+        time.sleep(1)
+
+    out = process.stdout.read()
+    process.stdout.close()
+    # print("done!", len(out), "bytes")
+    data = out.decode("utf-8", errors="ignore").split("\n")
+    return find_arg(source, data)
+
+def find_build_args_make(source):
+    make_exe = "make"
+    process = subprocess.Popen([make_exe, "--always-make", "--dry-run", "--keep-going", "VERBOSE=1"],
+                                stdout=subprocess.PIPE,
+                               )
+    while process.poll():
+        time.sleep(1)
+
+    out = process.stdout.read()
+    process.stdout.close()
+
+    # print("done!", len(out), "bytes")
+    data = out.decode("utf-8", errors="ignore").split("\n")
+    return find_arg(source, data)
+
+def main():
+
+    # currently only supports ninja or makefiles
+    build_file_ninja = os.path.join(BUILD_DIR, "build.ninja")
+    build_file_make = os.path.join(BUILD_DIR, "Makefile")
+    if os.path.exists(build_file_ninja):
+        print("Using Ninja")
+        arg = find_build_args_ninja(SOURCE_FILE)
+    elif os.path.exists(build_file_make):
+        print("Using Make")
+        arg = find_build_args_make(SOURCE_FILE)
+    else:
+        sys.stderr.write("Can't find Ninja or Makefile (%r or %r), aborting" % (build_file_ninja, build_file_make))
+        return
+
+    if arg is None:
+        sys.stderr.write("Can't find file %r in build command output of %r, aborting" % (SOURCE_FILE, BUILD_DIR))
+        return
+
+    # now we need to get arg and modify it to produce assembler
+    arg_split = shlex.split(arg)
+
+    # get rid of: 'cd /a/b/c && ' prefix used by make (ninja doesn't need)
+    try:
+        i = arg_split.index("&&")
+    except ValueError:
+        i = -1
+    if i != -1:
+        del arg_split[:i + 1] 
+
+    if COMPILER_ID == 'GCC':
+        # remove arg pairs
+        for arg, n in (("-o", 2), ("-MF", 2), ("-MT", 2), ("-MMD", 1)):
+            if arg in arg_split:
+                i = arg_split.index(arg)
+                del arg_split[i : i + n]
+
+        # --- Switch debug for optimized ---
+        for arg, n in (("-O0", 1),
+                       ("-g", 1), ("-g1", 1), ("-g2", 1), ("-g3", 1),
+                       ("-ggdb", 1), ("-ggdb", 1), ("-ggdb1", 1), ("-ggdb2", 1), ("-ggdb3", 1),
+                       ("-fno-inline", 1),
+                       ("-DDEBUG", 1), ("-D_DEBUG", 1),
+                       ):
+            if arg in arg_split:
+                i = arg_split.index(arg)
+                del arg_split[i : i + n]
+
+        # add optimized args
+        arg_split += ["-O3", "-fomit-frame-pointer", "-DNDEBUG", "-Wno-error"]
+
+        # not essential but interesting to know
+        arg_split += ["-ftree-vectorizer-verbose=1"]
+
+        arg_split += ["-S"]
+        # arg_split += ["-masm=intel"]  # optional
+        # arg_split += ["-fverbose-asm"]  # optional but handy
+    else:
+        sys.stderr.write("Compiler %r not supported" % COMPILER_ID)
+        return
+
+    source_asm = SOURCE_FILE + ".asm"
+
+    # Never overwrite existing files
+    i = 1
+    while os.path.exists(source_asm):
+        source_asm = SOURCE_FILE + ".asm.%d" % i
+        i += 1
+
+    arg_split += ["-o", source_asm]
+
+    # print("Executing:", arg_split)
+    subprocess.call(arg_split)
+
+    if not os.path.exists(source_asm):
+        sys.stderr.write("Did not create %r from calling %r" % (source_asm, " ".join(arg_split)))
+        return
+    print("Running: %r" % " ".join(arg_split))
+    print("Created: %r" % source_asm)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/utils_ide/qtcreator/externaltools/qtc_assembler_preview.xml b/utils_ide/qtcreator/externaltools/qtc_assembler_preview.xml
new file mode 100644
index 0000000..c09a5c9
--- /dev/null
+++ b/utils_ide/qtcreator/externaltools/qtc_assembler_preview.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<externaltool id="qtc_assembler_preview">
+    <description>Create an assembler file from source (C/C++)</description>
+    <displayname>Assembler Preview</displayname>
+    <category>Compiler</category>
+    <executable output="showinpane" error="showinpane" modifiesdocument="no">
+        <path>qtc_assembler_preview.py</path>
+        <arguments>%{CurrentProject:BuildPath} %{CurrentDocument:FilePath}</arguments>
+        <workingdirectory>%{CurrentProject:BuildPath}</workingdirectory>
+    </executable>
+</externaltool>
-- 
GitLab