1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4#  xcmoc.py
5#  Run Qt moc on all classes that contain Q_OBJECT
6#
7#  Created by Jaakko Keränen on 2017-05-07.
8#  Copyright © 2017 Jaakko Keränen <jaakko.keranen@iki.fi>
9
10import sys, os, re, subprocess, hashlib
11
12IGNORED_HEADERS = ['glwindow.h']
13
14def contains_qobject(fn):
15    for line in open(fn, 'rt').readlines():
16        if 'Q_OBJECT' in line:
17            return True
18    return False
19
20def find_headers(dir_path):
21    headers = []
22    for fn in os.listdir(dir_path):
23        if fn in IGNORED_HEADERS: continue
24        file_path = os.path.join(dir_path, fn)
25        if os.path.isdir(file_path):
26            headers += find_headers(file_path)
27        elif fn.endswith('.h'):
28            if contains_qobject(file_path):
29                headers.append(os.path.abspath(file_path))
30    return headers
31
32# def find_source(name, dir_path = os.path.join(sys.argv[1], 'src')):
33#     for fn in os.listdir(dir_path):
34#         file_path = os.path.join(dir_path, fn)
35#         if os.path.isdir(file_path):
36#             found = find_source(name, file_path)
37#             if found: return found
38#         elif fn == name[:-2] + '.cpp':
39#             return os.path.abspath(file_path)
40#     return None
41
42def md5sum(text):
43    m = hashlib.md5()
44    m.update(text.encode())
45    m.update(os.getenv('GCC_PREPROCESSOR_DEFINITIONS').encode())
46    m.update(os.getenv('HEADER_SEARCH_PATHS').encode())
47    return m.hexdigest()
48
49#print "Running moc in", sys.argv[1]
50OUT_DIR = os.getenv('PROJECT_TEMP_DIR')
51try:
52    os.makedirs(OUT_DIR)
53except:
54    pass
55
56headers = find_headers(sys.argv[1])
57
58QT_DIR = os.getenv('QT_DIR')
59defines = ['-D%s' % d for d in os.getenv('GCC_PREPROCESSOR_DEFINITIONS').split()]
60includes = ['-I%s' % d for d in re.split(r"(?<=\w)\s", os.getenv('HEADER_SEARCH_PATHS'))]
61args = ['%s/bin/moc' % QT_DIR] + defines + includes
62
63compilation = ['/* This file is autogenerated by xcmoc.py */']
64
65for header in headers:
66    header_name = os.path.basename(header)
67    dir_path = os.path.dirname(header)
68    moc_name = '%s_moc_%s.cpp' % (md5sum(dir_path), header_name[:-2])
69    moc_path = os.path.join(OUT_DIR, moc_name)
70
71    compilation.append('#include "%s"' % moc_name)
72
73    # Check timestamps.
74    if not os.path.exists(moc_path) or \
75            os.path.getmtime(header) > os.path.getmtime(moc_path):
76        print 'Running moc:', header_name
77        subprocess.check_output(args + [header, '-o', moc_path], stderr=subprocess.STDOUT)
78
79comp_path = os.path.join(OUT_DIR, '%s_moc_compilation.cpp' % os.getenv('TARGETNAME'))
80
81open(comp_path, 'wt').write("\n".join(compilation) + "\n")
82
83