3 """Helps to keep BUILD.gn files in sync with the corresponding CMakeLists.txt.
5 For each BUILD.gn file in the tree, checks if the list of cpp files in
6 it is identical to the list of cpp files in the corresponding CMakeLists.txt
7 file, and prints the difference if not.
9 Also checks that each CMakeLists.txt file below unittests/ folders that define
10 binaries have corresponding BUILD.gn files.
13 from __future__
import print_function
21 def sync_source_lists():
22 # Use shell=True on Windows in case git is a bat file.
23 gn_files
= subprocess
.check_output(['git', 'ls-files', '*BUILD.gn'],
24 shell
=os
.name
== 'nt').splitlines()
26 # Matches e.g. | "foo.cpp",|, captures |foo| in group 1.
27 gn_cpp_re
= re
.compile(r
'^\s*"([^"]+\.(?:cpp|c|h|S))",$', re
.MULTILINE
)
28 # Matches e.g. | foo.cpp|, captures |foo| in group 1.
29 cmake_cpp_re
= re
.compile(r
'^\s*([A-Za-z_0-9./-]+\.(?:cpp|c|h|S))$',
33 for gn_file
in gn_files
:
34 # The CMakeLists.txt for llvm/utils/gn/secondary/foo/BUILD.gn is
35 # directly at foo/CMakeLists.txt.
36 strip_prefix
= 'llvm/utils/gn/secondary/'
37 if not gn_file
.startswith(strip_prefix
):
39 cmake_file
= os
.path
.join(
40 os
.path
.dirname(gn_file
[len(strip_prefix
):]), 'CMakeLists.txt')
41 if not os
.path
.exists(cmake_file
):
44 def get_sources(source_re
, text
):
45 return set([m
.group(1) for m
in source_re
.finditer(text
)])
46 gn_cpp
= get_sources(gn_cpp_re
, open(gn_file
).read())
47 cmake_cpp
= get_sources(cmake_cpp_re
, open(cmake_file
).read())
49 if gn_cpp
== cmake_cpp
:
54 add
= sorted(cmake_cpp
- gn_cpp
)
56 print('add:\n' + '\n'.join(' "%s",' % a
for a
in add
))
57 remove
= sorted(gn_cpp
- cmake_cpp
)
59 print('remove:\n' + '\n'.join(remove
))
65 # Matches e.g. |add_llvm_unittest_with_input_files|.
66 unittest_re
= re
.compile(r
'^add_\S+_unittest', re
.MULTILINE
)
68 checked
= [ 'clang', 'clang-tools-extra', 'lld', 'llvm' ]
71 for root
, _
, _
in os
.walk(os
.path
.join(c
, 'unittests')):
72 cmake_file
= os
.path
.join(root
, 'CMakeLists.txt')
73 if not os
.path
.exists(cmake_file
):
75 if not unittest_re
.search(open(cmake_file
).read()):
76 continue # Skip CMake files that just add subdirectories.
77 gn_file
= os
.path
.join('llvm/utils/gn/secondary', root
, 'BUILD.gn')
78 if not os
.path
.exists(gn_file
):
80 print('missing GN file %s for unittest CMake file %s' %
81 (gn_file
, cmake_file
))
86 src
= sync_source_lists()
87 tests
= sync_unittests()
93 if __name__
== '__main__':