]> git.ipfire.org Git - thirdparty/glibc.git/blame - scripts/sort-makefile-lines.py
Use --enable-obsolete in build-many-glibcs.py for nios2-linux-gnu
[thirdparty/glibc.git] / scripts / sort-makefile-lines.py
CommitLineData
1270549a
CD
1#!/usr/bin/python3
2# Sort Makefile lines as expected by project policy.
dff8da6b 3# Copyright (C) 2023-2024 Free Software Foundation, Inc.
1270549a
CD
4# This file is part of the GNU C Library.
5#
6# The GNU C Library is free software; you can redistribute it and/or
7# modify it under the terms of the GNU Lesser General Public
8# License as published by the Free Software Foundation; either
9# version 2.1 of the License, or (at your option) any later version.
10#
11# The GNU C Library is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14# Lesser General Public License for more details.
15#
16# You should have received a copy of the GNU Lesser General Public
17# License along with the GNU C Library; if not, see
18# <https://www.gnu.org/licenses/>.
19
20# The project consensus is to split Makefile variable assignment
21# across multiple lines with one value per line. The values are
22# then sorted as described below, and terminated with a special
23# list termination marker. This splitting makes it much easier
24# to add new tests to the list since they become just a single
25# line insertion. It also makes backports and merges easier
26# since the new test may not conflict due to the ordering.
27#
28# Consensus discussion:
29# https://inbox.sourceware.org/libc-alpha/f6406204-84f5-adb1-d00e-979ebeebbbde@redhat.com/
30#
31# To support cleaning up Makefiles we created this program to
32# help sort existing lists converted to the new format.
33#
34# The program takes as input the Makefile to sort correctly,
35# and the output file to write the correctly sorted output
36# (it can be the same file).
37#
38# Sorting is only carried out between two special markers:
39# (a) Marker start is '<variable> += \' (or '= \', or ':= \')
40# (b) Marker end is ' # <variable>' (whitespace matters)
2cbeda84 41# With everything between (a) and (b) being sorted accordingly.
1270549a
CD
42#
43# You can use it like this:
44# $ scripts/sort-makefile-lines.py < elf/Makefile > elf/Makefile.tmp
45# $ mv elf/Makefile.tmp elf/Makefile
46#
47# The Makefile lines in the project are sorted using the
48# following rules:
49# - All lines are sorted as-if `LC_COLLATE=C sort`
50# - Lines that have a numeric suffix and whose leading prefix
51# matches exactly are sorted according the numeric suffix
52# in increasing numerical order.
53#
54# For example:
55# ~~~
56# tests += \
57# test-a \
58# test-b \
59# test-b1 \
60# test-b2 \
61# test-b10 \
62# test-b20 \
63# test-b100 \
64# # tests
65# ~~~
66# This example shows tests sorted alphabetically, followed
67# by a numeric suffix sort in increasing numeric order.
68#
69# Cleanups:
70# - Tests that end in "a" or "b" variants should be renamed to
71# end in just the numerical value. For example 'tst-mutex7robust'
72# should be renamed to 'tst-mutex12' (the highest numbered test)
73# or 'tst-robust11' (the highest numbered test) in order to get
74# reasonable ordering.
75# - Modules that end in "mod" or "mod1" should be renamed. For
76# example 'tst-atfork2mod' should be renamed to 'tst-mod-atfork2'
77# (test module for atfork2). If there are more than one module
78# then they should be named with a suffix that uses [0-9] first
79# then [A-Z] next for a total of 36 possible modules per test.
80# No manually listed test currently uses more than that (though
81# automatically generated tests may; they don't need sorting).
82# - Avoid including another test and instead refactor into common
2cbeda84 83# code with all tests including the common code, then give the
1270549a
CD
84# tests unique names.
85#
86# If you have a Makefile that needs converting, then you can
87# quickly split the values into one-per-line, ensure the start
88# and end markers are in place, and then run the script to
89# sort the values.
90
91import sys
92import locale
93import re
94import functools
95
96def glibc_makefile_numeric(string1, string2):
97 # Check if string1 has a numeric suffix.
98 var1 = re.search(r'([0-9]+) \\$', string1)
99 var2 = re.search(r'([0-9]+) \\$', string2)
100 if var1 and var2:
101 if string1[0:var1.span()[0]] == string2[0:var2.span()[0]]:
102 # string1 and string2 both share a prefix and
103 # have a numeric suffix that can be compared.
104 # Sort order is based on the numeric suffix.
b0528456
CD
105 # If the suffix is the same return 0, otherwise
106 # > 0 for greater-than, and < 0 for less-than.
107 # This is equivalent to the numerical difference.
108 return int(var1.group(1)) - int(var2.group(1))
1270549a
CD
109 # Default to strcoll.
110 return locale.strcoll(string1, string2)
111
112def sort_lines(lines):
113
114 # Use the C locale for language independent collation.
115 locale.setlocale (locale.LC_ALL, "C")
116
117 # Sort using a glibc-specific sorting function.
118 lines = sorted(lines, key=functools.cmp_to_key(glibc_makefile_numeric))
119
120 return lines
121
122def sort_makefile_lines():
123
124 # Read the whole Makefile.
125 lines = sys.stdin.readlines()
126
127 # Build a list of all start markers (tuple includes name).
128 startmarks = []
129 for i in range(len(lines)):
130 # Look for things like "var = \", "var := \" or "var += \"
131 # to start the sorted list.
6a2512bf 132 var = re.search(r'^([-_a-zA-Z0-9]*) [\+:]?\= \\$', lines[i])
1270549a
CD
133 if var:
134 # Remember the index and the name.
135 startmarks.append((i, var.group(1)))
136
137 # For each start marker try to find a matching end mark
138 # and build a block that needs sorting. The end marker
139 # must have the matching comment name for it to be valid.
140 rangemarks = []
141 for sm in startmarks:
142 # Look for things like " # var" to end the sorted list.
6a2512bf 143 reg = r'^ *# ' + sm[1] + r'$'
1270549a
CD
144 for j in range(sm[0] + 1, len(lines)):
145 if re.search(reg, lines[j]):
2cbeda84 146 # Remember the block to sort (inclusive).
1270549a
CD
147 rangemarks.append((sm[0] + 1, j))
148 break
149
150 # We now have a list of all ranges that need sorting.
151 # Sort those ranges (inclusive).
152 for r in rangemarks:
153 lines[r[0]:r[1]] = sort_lines(lines[r[0]:r[1]])
154
155 # Output the whole list with sorted lines to stdout.
156 [sys.stdout.write(line) for line in lines]
157
158
159def main(argv):
160 sort_makefile_lines ()
161
162if __name__ == '__main__':
163 main(sys.argv[1:])