ENH: Update FreeFOAM contributions to GPL v3
[freefoam.git] / data / utilities / checkApi.py.in
blob225ca2b8da8677a95f0515d098ca5e39146270e8
1 #!@PYTHON_EXECUTABLE@
2 #-------------------------------------------------------------------------------
3 # ______ _ ____ __ __
4 # | ____| _| |_ / __ \ /\ | \/ |
5 # | |__ _ __ ___ ___ / \| | | | / \ | \ / |
6 # | __| '__/ _ \/ _ ( (| |) ) | | |/ /\ \ | |\/| |
7 # | | | | | __/ __/\_ _/| |__| / ____ \| | | |
8 # |_| |_| \___|\___| |_| \____/_/ \_\_| |_|
10 # FreeFOAM: The Cross-Platform CFD Toolkit
12 # Copyright (C) 2008-2012 Michael Wild <themiwi@users.sf.net>
13 # Gerber van der Graaf <gerber_graaf@users.sf.net>
14 #-------------------------------------------------------------------------------
15 # License
16 # This file is part of FreeFOAM.
18 # FreeFOAM is free software: you can redistribute it and/or modify it
19 # under the terms of the GNU General Public License as published by the
20 # Free Software Foundation, either version 3 of the License, or (at your
21 # option) any later version.
23 # FreeFOAM is distributed in the hope that it will be useful, but WITHOUT
24 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 # for more details.
28 # You should have received a copy of the GNU General Public License
29 # along with FreeFOAM. If not, see <http://www.gnu.org/licenses/>.
31 # Script
32 # checkApi.py
34 # Description
35 # Verifies that all required headers (and only those) are installed.
37 # This utility script first searches through all application sources in the
38 # distribution and indexes all included files. It discards local/relative
39 # includes, and then searches for the remaining headers in the installation
40 # directory. It will report unused and missing headers in the installation.
42 # Bugs
43 # At the moment results in a *lot* of unused headers in the installation,
44 # simply because they are not ultimately included by an application. Not
45 # sure what a good policy would be...
47 #------------------------------------------------------------------------------
49 import sys
50 import os
51 import os.path
52 import re
54 appdir = '@CMAKE_SOURCE_DIR@/applications'
55 srcdir = '@CMAKE_SOURCE_DIR@/src'
56 incdir = os.path.normpath('@FOAM_INSTALL_HEADER_PATH@')
57 prefixes = (incdir, '/usr/include/c++/4.5', '/usr/include')
58 srcRe = re.compile(r'\.(?:[CH]|[ch](?:[px]{2})?)$')
59 commentRe = re.compile(r'//.*?$|/\*.*?\*/', re.S|re.M)
60 includeRe = re.compile(
61 r'^\s*#\s*include\s+(?:(?P<local>")|(?P<system><))(?P<include>[^">]+)'+
62 r'(?(local)")(?(system)>)',
63 re.M)
64 blacklist = (
65 'standards.h',
66 'sys/endian.h',
67 'stream.h',
68 'libccmio/ccmio.h',
69 'windows.h',
72 def locateHdr(f, h, local=True, system=True):
73 if local:
74 fullh = os.path.join(os.path.dirname(f), h)
75 if os.path.isfile(fullh):
76 return fullh
77 if system:
78 for p in prefixes:
79 fullh = os.path.join(p, h)
80 if os.path.isfile(fullh):
81 return fullh
82 return None
84 # find all headers included by applications, check for their existence and
85 # record FreeFOAM headers in reqHdrs
86 reqHdrs = set()
87 missingHdrs = set()
88 for parent, dirs, files in os.walk(appdir):
89 files = filter(srcRe.search, files)
90 for f in files:
91 text = commentRe.sub('',
92 ''.join(open(os.path.join(parent, f), 'rt').readlines()))
93 for m in includeRe.finditer(text):
94 if m.group('system') is not None:
95 h = m.group('include')
96 if h not in blacklist:
97 hh = locateHdr('', h, local=False, system=True)
98 if hh is not None:
99 if incdir == os.path.normpath(hh.replace(h, '')):
100 reqHdrs.add(hh)
101 else:
102 missingHdrs.add(h)
104 # find recursively included headers, and add to allReqHdrs
105 allReqHdrs = set(reqHdrs)
106 fstack = list(reqHdrs)
107 while len(fstack):
108 f = fstack.pop()
109 text = commentRe.sub('', ''.join(open(f, 'rt').readlines()))
110 for m in includeRe.finditer(text):
111 h = m.group('include')
112 if h not in blacklist:
113 hh = locateHdr(f, h, m.group('local')!=None, m.group('system')!=None)
114 if hh is not None:
115 p = os.path.normpath(hh.replace(h, ''))
116 nh = os.path.normpath(hh)
117 if incdir == p and nh not in allReqHdrs:
118 allReqHdrs.add(nh)
119 fstack.append(nh)
120 else:
121 missingHdrs.add(h)
123 # now find all installed headers and record unused headers in unusedHdrs
124 unusedHdrs = set()
125 unknownFiles = []
126 for parent, dirs, files in os.walk(incdir):
127 for f in files:
128 ff = os.path.join(parent, f)
129 if srcRe.search(ff) is not None:
130 if ff not in allReqHdrs:
131 unusedHdrs.add(ff)
132 else:
133 unknownFiles.append(ff)
135 # print results
136 for t, s in (
137 ('Unused headers', unusedHdrs),
138 ('Missing headers', missingHdrs),
139 ('Unknown files', unknownFiles),
141 l = list(s)
142 l.sort()
143 sys.stderr.write(t+':\n\t'+'\n\t'.join(l)+'\n\n')
145 # ------------------------- vim: set sw=3 sts=3 et: --------------- end-of-file