diff options
-rw-r--r-- | meta/lib/oeqa/selftest/devtool.py | 2 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/recipetool.py | 2 | ||||
-rw-r--r-- | scripts/lib/recipetool/create.py | 130 | ||||
-rw-r--r-- | scripts/lib/recipetool/create_buildsys.py | 282 | ||||
-rw-r--r-- | scripts/lib/recipetool/create_buildsys_python.py | 2 |
5 files changed, 344 insertions, 74 deletions
diff --git a/meta/lib/oeqa/selftest/devtool.py b/meta/lib/oeqa/selftest/devtool.py index 0a44ae71c8..8faea93784 100644 --- a/meta/lib/oeqa/selftest/devtool.py +++ b/meta/lib/oeqa/selftest/devtool.py | |||
@@ -279,7 +279,7 @@ class DevtoolTests(DevtoolBase): | |||
279 | self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named') | 279 | self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named') |
280 | checkvars = {} | 280 | checkvars = {} |
281 | checkvars['S'] = '${WORKDIR}/git' | 281 | checkvars['S'] = '${WORKDIR}/git' |
282 | checkvars['PV'] = '1.0+git${SRCPV}' | 282 | checkvars['PV'] = '1.11+git${SRCPV}' |
283 | checkvars['SRC_URI'] = url | 283 | checkvars['SRC_URI'] = url |
284 | checkvars['SRCREV'] = '${AUTOREV}' | 284 | checkvars['SRCREV'] = '${AUTOREV}' |
285 | self._test_recipe_contents(recipefile, checkvars, []) | 285 | self._test_recipe_contents(recipefile, checkvars, []) |
diff --git a/meta/lib/oeqa/selftest/recipetool.py b/meta/lib/oeqa/selftest/recipetool.py index b1f1d2ab90..bbfce7c394 100644 --- a/meta/lib/oeqa/selftest/recipetool.py +++ b/meta/lib/oeqa/selftest/recipetool.py | |||
@@ -395,7 +395,7 @@ class RecipetoolTests(RecipetoolBase): | |||
395 | checkvars['LICENSE'] = 'LGPLv2.1' | 395 | checkvars['LICENSE'] = 'LGPLv2.1' |
396 | checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=7fbc338309ac38fefcd64b04bb903e34' | 396 | checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=7fbc338309ac38fefcd64b04bb903e34' |
397 | checkvars['S'] = '${WORKDIR}/git' | 397 | checkvars['S'] = '${WORKDIR}/git' |
398 | checkvars['PV'] = '1.0+git${SRCPV}' | 398 | checkvars['PV'] = '1.11+git${SRCPV}' |
399 | checkvars['SRC_URI'] = srcuri | 399 | checkvars['SRC_URI'] = srcuri |
400 | checkvars['DEPENDS'] = 'libpng pango libx11 libxext jpeg' | 400 | checkvars['DEPENDS'] = 'libpng pango libx11 libxext jpeg' |
401 | inherits = ['autotools', 'pkgconfig'] | 401 | inherits = ['autotools', 'pkgconfig'] |
diff --git a/scripts/lib/recipetool/create.py b/scripts/lib/recipetool/create.py index 5c249ab0c6..6c7b9fd7e8 100644 --- a/scripts/lib/recipetool/create.py +++ b/scripts/lib/recipetool/create.py | |||
@@ -41,10 +41,17 @@ def tinfoil_init(instance): | |||
41 | 41 | ||
42 | class RecipeHandler(): | 42 | class RecipeHandler(): |
43 | @staticmethod | 43 | @staticmethod |
44 | def checkfiles(path, speclist): | 44 | def checkfiles(path, speclist, recursive=False): |
45 | results = [] | 45 | results = [] |
46 | for spec in speclist: | 46 | if recursive: |
47 | results.extend(glob.glob(os.path.join(path, spec))) | 47 | for root, _, files in os.walk(path): |
48 | for fn in files: | ||
49 | for spec in speclist: | ||
50 | if fnmatch.fnmatch(fn, spec): | ||
51 | results.append(os.path.join(root, fn)) | ||
52 | else: | ||
53 | for spec in speclist: | ||
54 | results.extend(glob.glob(os.path.join(path, spec))) | ||
48 | return results | 55 | return results |
49 | 56 | ||
50 | def genfunction(self, outlines, funcname, content, python=False, forcespace=False): | 57 | def genfunction(self, outlines, funcname, content, python=False, forcespace=False): |
@@ -70,10 +77,14 @@ class RecipeHandler(): | |||
70 | outlines.append('}') | 77 | outlines.append('}') |
71 | outlines.append('') | 78 | outlines.append('') |
72 | 79 | ||
73 | def process(self, srctree, classes, lines_before, lines_after, handled): | 80 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
74 | return False | 81 | return False |
75 | 82 | ||
76 | 83 | ||
84 | def validate_pv(pv): | ||
85 | if not pv or '_version' in pv.lower() or pv[0] not in '0123456789': | ||
86 | return False | ||
87 | return True | ||
77 | 88 | ||
78 | def supports_srcrev(uri): | 89 | def supports_srcrev(uri): |
79 | localdata = bb.data.createCopy(tinfoil.config_data) | 90 | localdata = bb.data.createCopy(tinfoil.config_data) |
@@ -152,7 +163,12 @@ def create_recipe(args): | |||
152 | srcuri = '' | 163 | srcuri = '' |
153 | srctree = args.source | 164 | srctree = args.source |
154 | 165 | ||
155 | outfile = args.outfile | 166 | if args.outfile and os.path.isdir(args.outfile): |
167 | outfile = None | ||
168 | outdir = args.outfile | ||
169 | else: | ||
170 | outfile = args.outfile | ||
171 | outdir = None | ||
156 | if outfile and outfile != '-': | 172 | if outfile and outfile != '-': |
157 | if os.path.exists(outfile): | 173 | if os.path.exists(outfile): |
158 | logger.error('Output file %s already exists' % outfile) | 174 | logger.error('Output file %s already exists' % outfile) |
@@ -196,28 +212,29 @@ def create_recipe(args): | |||
196 | lines_before.append('') | 212 | lines_before.append('') |
197 | 213 | ||
198 | # FIXME This is kind of a hack, we probably ought to be using bitbake to do this | 214 | # FIXME This is kind of a hack, we probably ought to be using bitbake to do this |
199 | # we'd also want a way to automatically set outfile based upon auto-detecting these values from the source if possible | 215 | pn = None |
200 | recipefn = os.path.splitext(os.path.basename(outfile))[0] | 216 | pv = None |
201 | fnsplit = recipefn.split('_') | 217 | if outfile: |
202 | if len(fnsplit) > 1: | 218 | recipefn = os.path.splitext(os.path.basename(outfile))[0] |
203 | pn = fnsplit[0] | 219 | fnsplit = recipefn.split('_') |
204 | pv = fnsplit[1] | 220 | if len(fnsplit) > 1: |
205 | else: | 221 | pn = fnsplit[0] |
206 | pn = recipefn | 222 | pv = fnsplit[1] |
207 | pv = None | 223 | else: |
224 | pn = recipefn | ||
208 | 225 | ||
209 | if args.version: | 226 | if args.version: |
210 | pv = args.version | 227 | pv = args.version |
211 | 228 | ||
229 | if args.name: | ||
230 | pn = args.name | ||
231 | |||
212 | if pv and pv not in 'git svn hg'.split(): | 232 | if pv and pv not in 'git svn hg'.split(): |
213 | realpv = pv | 233 | realpv = pv |
214 | else: | 234 | else: |
215 | realpv = None | 235 | realpv = None |
216 | 236 | ||
217 | if srcuri: | 237 | if not srcuri: |
218 | if realpv: | ||
219 | srcuri = srcuri.replace(realpv, '${PV}') | ||
220 | else: | ||
221 | lines_before.append('# No information for SRC_URI yet (only an external source tree was specified)') | 238 | lines_before.append('# No information for SRC_URI yet (only an external source tree was specified)') |
222 | lines_before.append('SRC_URI = "%s"' % srcuri) | 239 | lines_before.append('SRC_URI = "%s"' % srcuri) |
223 | (md5value, sha256value) = checksums | 240 | (md5value, sha256value) = checksums |
@@ -232,13 +249,7 @@ def create_recipe(args): | |||
232 | lines_before.append('SRCREV = "%s"' % srcrev) | 249 | lines_before.append('SRCREV = "%s"' % srcrev) |
233 | lines_before.append('') | 250 | lines_before.append('') |
234 | 251 | ||
235 | if srcsubdir and pv: | ||
236 | if srcsubdir == "%s-%s" % (pn, pv): | ||
237 | # This would be the default, so we don't need to set S in the recipe | ||
238 | srcsubdir = '' | ||
239 | if srcsubdir: | 252 | if srcsubdir: |
240 | if pv and pv not in 'git svn hg'.split(): | ||
241 | srcsubdir = srcsubdir.replace(pv, '${PV}') | ||
242 | lines_before.append('S = "${WORKDIR}/%s"' % srcsubdir) | 253 | lines_before.append('S = "${WORKDIR}/%s"' % srcsubdir) |
243 | lines_before.append('') | 254 | lines_before.append('') |
244 | 255 | ||
@@ -276,8 +287,74 @@ def create_recipe(args): | |||
276 | classes.append('bin_package') | 287 | classes.append('bin_package') |
277 | handled.append('buildsystem') | 288 | handled.append('buildsystem') |
278 | 289 | ||
290 | extravalues = {} | ||
279 | for handler in handlers: | 291 | for handler in handlers: |
280 | handler.process(srctree, classes, lines_before, lines_after, handled) | 292 | handler.process(srctree, classes, lines_before, lines_after, handled, extravalues) |
293 | |||
294 | if not realpv: | ||
295 | realpv = extravalues.get('PV', None) | ||
296 | if realpv: | ||
297 | if not validate_pv(realpv): | ||
298 | realpv = None | ||
299 | else: | ||
300 | realpv = realpv.lower().split()[0] | ||
301 | if '_' in realpv: | ||
302 | realpv = realpv.replace('_', '-') | ||
303 | if not pn: | ||
304 | pn = extravalues.get('PN', None) | ||
305 | if pn: | ||
306 | if pn.startswith('GNU '): | ||
307 | pn = pn[4:] | ||
308 | if ' ' in pn: | ||
309 | # Probably a descriptive identifier rather than a proper name | ||
310 | pn = None | ||
311 | else: | ||
312 | pn = pn.lower() | ||
313 | if '_' in pn: | ||
314 | pn = pn.replace('_', '-') | ||
315 | |||
316 | if not outfile: | ||
317 | if not pn: | ||
318 | logger.error('Unable to determine short program name from source tree - please specify name with -N/--name or output file name with -o/--outfile') | ||
319 | # devtool looks for this specific exit code, so don't change it | ||
320 | sys.exit(15) | ||
321 | else: | ||
322 | if srcuri and srcuri.startswith(('git://', 'hg://', 'svn://')): | ||
323 | outfile = '%s_%s.bb' % (pn, srcuri.split(':', 1)[0]) | ||
324 | elif realpv: | ||
325 | outfile = '%s_%s.bb' % (pn, realpv) | ||
326 | else: | ||
327 | outfile = '%s.bb' % pn | ||
328 | if outdir: | ||
329 | outfile = os.path.join(outdir, outfile) | ||
330 | # We need to check this again | ||
331 | if os.path.exists(outfile): | ||
332 | logger.error('Output file %s already exists' % outfile) | ||
333 | sys.exit(1) | ||
334 | |||
335 | lines = lines_before | ||
336 | lines_before = [] | ||
337 | skipblank = True | ||
338 | for line in lines: | ||
339 | if skipblank: | ||
340 | skipblank = False | ||
341 | if not line: | ||
342 | continue | ||
343 | if line.startswith('S = '): | ||
344 | if realpv and pv not in 'git svn hg'.split(): | ||
345 | line = line.replace(realpv, '${PV}') | ||
346 | if pn: | ||
347 | line = line.replace(pn, '${BPN}') | ||
348 | if line == 'S = "${WORKDIR}/${BPN}-${PV}"': | ||
349 | skipblank = True | ||
350 | continue | ||
351 | elif line.startswith('SRC_URI = '): | ||
352 | if realpv: | ||
353 | line = line.replace(realpv, '${PV}') | ||
354 | elif line.startswith('PV = '): | ||
355 | if realpv: | ||
356 | line = re.sub('"[^+]*\+', '"%s+' % realpv, line) | ||
357 | lines_before.append(line) | ||
281 | 358 | ||
282 | outlines = [] | 359 | outlines = [] |
283 | outlines.extend(lines_before) | 360 | outlines.extend(lines_before) |
@@ -469,9 +546,10 @@ def register_commands(subparsers): | |||
469 | help='Create a new recipe', | 546 | help='Create a new recipe', |
470 | description='Creates a new recipe from a source tree') | 547 | description='Creates a new recipe from a source tree') |
471 | parser_create.add_argument('source', help='Path or URL to source') | 548 | parser_create.add_argument('source', help='Path or URL to source') |
472 | parser_create.add_argument('-o', '--outfile', help='Specify filename for recipe to create', required=True) | 549 | parser_create.add_argument('-o', '--outfile', help='Specify filename for recipe to create') |
473 | parser_create.add_argument('-m', '--machine', help='Make recipe machine-specific as opposed to architecture-specific', action='store_true') | 550 | parser_create.add_argument('-m', '--machine', help='Make recipe machine-specific as opposed to architecture-specific', action='store_true') |
474 | parser_create.add_argument('-x', '--extract-to', metavar='EXTRACTPATH', help='Assuming source is a URL, fetch it and extract it to the directory specified as %(metavar)s') | 551 | parser_create.add_argument('-x', '--extract-to', metavar='EXTRACTPATH', help='Assuming source is a URL, fetch it and extract it to the directory specified as %(metavar)s') |
552 | parser_create.add_argument('-N', '--name', help='Name to use within recipe (PN)') | ||
475 | parser_create.add_argument('-V', '--version', help='Version to use within recipe (PV)') | 553 | parser_create.add_argument('-V', '--version', help='Version to use within recipe (PV)') |
476 | parser_create.add_argument('-b', '--binary', help='Treat the source tree as something that should be installed verbatim (no compilation, same directory structure)', action='store_true') | 554 | parser_create.add_argument('-b', '--binary', help='Treat the source tree as something that should be installed verbatim (no compilation, same directory structure)', action='store_true') |
477 | parser_create.set_defaults(func=create_recipe) | 555 | parser_create.set_defaults(func=create_recipe) |
diff --git a/scripts/lib/recipetool/create_buildsys.py b/scripts/lib/recipetool/create_buildsys.py index 931ef3b33f..0aff59e229 100644 --- a/scripts/lib/recipetool/create_buildsys.py +++ b/scripts/lib/recipetool/create_buildsys.py | |||
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | import re | 18 | import re |
19 | import logging | 19 | import logging |
20 | from recipetool.create import RecipeHandler, read_pkgconfig_provides | 20 | from recipetool.create import RecipeHandler, read_pkgconfig_provides, validate_pv |
21 | 21 | ||
22 | logger = logging.getLogger('recipetool') | 22 | logger = logging.getLogger('recipetool') |
23 | 23 | ||
@@ -27,13 +27,17 @@ def tinfoil_init(instance): | |||
27 | global tinfoil | 27 | global tinfoil |
28 | tinfoil = instance | 28 | tinfoil = instance |
29 | 29 | ||
30 | |||
30 | class CmakeRecipeHandler(RecipeHandler): | 31 | class CmakeRecipeHandler(RecipeHandler): |
31 | def process(self, srctree, classes, lines_before, lines_after, handled): | 32 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
32 | if 'buildsystem' in handled: | 33 | if 'buildsystem' in handled: |
33 | return False | 34 | return False |
34 | 35 | ||
35 | if RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']): | 36 | if RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']): |
36 | classes.append('cmake') | 37 | classes.append('cmake') |
38 | values = CmakeRecipeHandler.extract_cmake_deps(lines_before, srctree, extravalues) | ||
39 | for var, value in values.iteritems(): | ||
40 | lines_before.append('%s = "%s"' % (var, value)) | ||
37 | lines_after.append('# Specify any options you want to pass to cmake using EXTRA_OECMAKE:') | 41 | lines_after.append('# Specify any options you want to pass to cmake using EXTRA_OECMAKE:') |
38 | lines_after.append('EXTRA_OECMAKE = ""') | 42 | lines_after.append('EXTRA_OECMAKE = ""') |
39 | lines_after.append('') | 43 | lines_after.append('') |
@@ -41,8 +45,26 @@ class CmakeRecipeHandler(RecipeHandler): | |||
41 | return True | 45 | return True |
42 | return False | 46 | return False |
43 | 47 | ||
48 | @staticmethod | ||
49 | def extract_cmake_deps(outlines, srctree, extravalues, cmakelistsfile=None): | ||
50 | values = {} | ||
51 | |||
52 | if cmakelistsfile: | ||
53 | srcfiles = [cmakelistsfile] | ||
54 | else: | ||
55 | srcfiles = RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']) | ||
56 | |||
57 | proj_re = re.compile('project\(([^)]*)\)', re.IGNORECASE) | ||
58 | with open(srcfiles[0], 'r') as f: | ||
59 | for line in f: | ||
60 | res = proj_re.match(line.strip()) | ||
61 | if res: | ||
62 | extravalues['PN'] = res.group(1).split()[0] | ||
63 | |||
64 | return values | ||
65 | |||
44 | class SconsRecipeHandler(RecipeHandler): | 66 | class SconsRecipeHandler(RecipeHandler): |
45 | def process(self, srctree, classes, lines_before, lines_after, handled): | 67 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
46 | if 'buildsystem' in handled: | 68 | if 'buildsystem' in handled: |
47 | return False | 69 | return False |
48 | 70 | ||
@@ -56,7 +78,7 @@ class SconsRecipeHandler(RecipeHandler): | |||
56 | return False | 78 | return False |
57 | 79 | ||
58 | class QmakeRecipeHandler(RecipeHandler): | 80 | class QmakeRecipeHandler(RecipeHandler): |
59 | def process(self, srctree, classes, lines_before, lines_after, handled): | 81 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
60 | if 'buildsystem' in handled: | 82 | if 'buildsystem' in handled: |
61 | return False | 83 | return False |
62 | 84 | ||
@@ -67,14 +89,14 @@ class QmakeRecipeHandler(RecipeHandler): | |||
67 | return False | 89 | return False |
68 | 90 | ||
69 | class AutotoolsRecipeHandler(RecipeHandler): | 91 | class AutotoolsRecipeHandler(RecipeHandler): |
70 | def process(self, srctree, classes, lines_before, lines_after, handled): | 92 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
71 | if 'buildsystem' in handled: | 93 | if 'buildsystem' in handled: |
72 | return False | 94 | return False |
73 | 95 | ||
74 | autoconf = False | 96 | autoconf = False |
75 | if RecipeHandler.checkfiles(srctree, ['configure.ac', 'configure.in']): | 97 | if RecipeHandler.checkfiles(srctree, ['configure.ac', 'configure.in']): |
76 | autoconf = True | 98 | autoconf = True |
77 | values = AutotoolsRecipeHandler.extract_autotools_deps(lines_before, srctree) | 99 | values = AutotoolsRecipeHandler.extract_autotools_deps(lines_before, srctree, extravalues) |
78 | classes.extend(values.pop('inherit', '').split()) | 100 | classes.extend(values.pop('inherit', '').split()) |
79 | for var, value in values.iteritems(): | 101 | for var, value in values.iteritems(): |
80 | lines_before.append('%s = "%s"' % (var, value)) | 102 | lines_before.append('%s = "%s"' % (var, value)) |
@@ -88,6 +110,22 @@ class AutotoolsRecipeHandler(RecipeHandler): | |||
88 | autoconf = True | 110 | autoconf = True |
89 | break | 111 | break |
90 | 112 | ||
113 | if autoconf and not ('PV' in extravalues and 'PN' in extravalues): | ||
114 | # Last resort | ||
115 | conffile = RecipeHandler.checkfiles(srctree, ['configure']) | ||
116 | if conffile: | ||
117 | with open(conffile[0], 'r') as f: | ||
118 | for line in f: | ||
119 | line = line.strip() | ||
120 | if line.startswith('VERSION=') or line.startswith('PACKAGE_VERSION='): | ||
121 | pv = line.split('=')[1].strip('"\'') | ||
122 | if pv and not 'PV' in extravalues and validate_pv(pv): | ||
123 | extravalues['PV'] = pv | ||
124 | elif line.startswith('PACKAGE_NAME=') or line.startswith('PACKAGE='): | ||
125 | pn = line.split('=')[1].strip('"\'') | ||
126 | if pn and not 'PN' in extravalues: | ||
127 | extravalues['PN'] = pn | ||
128 | |||
91 | if autoconf: | 129 | if autoconf: |
92 | lines_before.append('# NOTE: if this software is not capable of being built in a separate build directory') | 130 | lines_before.append('# NOTE: if this software is not capable of being built in a separate build directory') |
93 | lines_before.append('# from the source, you should replace autotools with autotools-brokensep in the') | 131 | lines_before.append('# from the source, you should replace autotools with autotools-brokensep in the') |
@@ -102,7 +140,7 @@ class AutotoolsRecipeHandler(RecipeHandler): | |||
102 | return False | 140 | return False |
103 | 141 | ||
104 | @staticmethod | 142 | @staticmethod |
105 | def extract_autotools_deps(outlines, srctree, acfile=None): | 143 | def extract_autotools_deps(outlines, srctree, extravalues=None, acfile=None): |
106 | import shlex | 144 | import shlex |
107 | import oe.package | 145 | import oe.package |
108 | 146 | ||
@@ -122,6 +160,9 @@ class AutotoolsRecipeHandler(RecipeHandler): | |||
122 | lib_re = re.compile('AC_CHECK_LIB\(\[?([a-zA-Z0-9]*)\]?, .*') | 160 | lib_re = re.compile('AC_CHECK_LIB\(\[?([a-zA-Z0-9]*)\]?, .*') |
123 | progs_re = re.compile('_PROGS?\(\[?[a-zA-Z0-9]*\]?, \[?([^,\]]*)\]?[),].*') | 161 | progs_re = re.compile('_PROGS?\(\[?[a-zA-Z0-9]*\]?, \[?([^,\]]*)\]?[),].*') |
124 | dep_re = re.compile('([^ ><=]+)( [<>=]+ [^ ><=]+)?') | 162 | dep_re = re.compile('([^ ><=]+)( [<>=]+ [^ ><=]+)?') |
163 | ac_init_re = re.compile('AC_INIT\(([^,]+), *([^,]+)[,)].*') | ||
164 | am_init_re = re.compile('AM_INIT_AUTOMAKE\(([^,]+), *([^,]+)[,)].*') | ||
165 | define_re = re.compile(' *(m4_)?define\(([^,]+), *([^,]+)\)') | ||
125 | 166 | ||
126 | # Build up lib library->package mapping | 167 | # Build up lib library->package mapping |
127 | shlib_providers = oe.package.read_shlib_providers(tinfoil.config_data) | 168 | shlib_providers = oe.package.read_shlib_providers(tinfoil.config_data) |
@@ -157,55 +198,157 @@ class AutotoolsRecipeHandler(RecipeHandler): | |||
157 | else: | 198 | else: |
158 | raise | 199 | raise |
159 | 200 | ||
201 | defines = {} | ||
202 | def subst_defines(value): | ||
203 | newvalue = value | ||
204 | for define, defval in defines.iteritems(): | ||
205 | newvalue = newvalue.replace(define, defval) | ||
206 | if newvalue != value: | ||
207 | return subst_defines(newvalue) | ||
208 | return value | ||
209 | |||
210 | def process_value(value): | ||
211 | value = value.replace('[', '').replace(']', '') | ||
212 | if value.startswith('m4_esyscmd(') or value.startswith('m4_esyscmd_s('): | ||
213 | cmd = subst_defines(value[value.index('(')+1:-1]) | ||
214 | try: | ||
215 | if '|' in cmd: | ||
216 | cmd = 'set -o pipefail; ' + cmd | ||
217 | stdout, _ = bb.process.run(cmd, cwd=srctree, shell=True) | ||
218 | ret = stdout.rstrip() | ||
219 | except bb.process.ExecutionError as e: | ||
220 | ret = '' | ||
221 | elif value.startswith('m4_'): | ||
222 | return None | ||
223 | ret = subst_defines(value) | ||
224 | if ret: | ||
225 | ret = ret.strip('"\'') | ||
226 | return ret | ||
227 | |||
160 | # Since a configure.ac file is essentially a program, this is only ever going to be | 228 | # Since a configure.ac file is essentially a program, this is only ever going to be |
161 | # a hack unfortunately; but it ought to be enough of an approximation | 229 | # a hack unfortunately; but it ought to be enough of an approximation |
162 | if acfile: | 230 | if acfile: |
163 | srcfiles = [acfile] | 231 | srcfiles = [acfile] |
164 | else: | 232 | else: |
165 | srcfiles = RecipeHandler.checkfiles(srctree, ['configure.ac', 'configure.in']) | 233 | srcfiles = RecipeHandler.checkfiles(srctree, ['acinclude.m4', 'configure.ac', 'configure.in']) |
234 | |||
166 | pcdeps = [] | 235 | pcdeps = [] |
167 | deps = [] | 236 | deps = [] |
168 | unmapped = [] | 237 | unmapped = [] |
169 | unmappedlibs = [] | 238 | unmappedlibs = [] |
170 | with open(srcfiles[0], 'r') as f: | 239 | |
171 | for line in f: | 240 | def process_macro(keyword, value): |
172 | if 'PKG_CHECK_MODULES' in line: | 241 | if keyword == 'PKG_CHECK_MODULES': |
173 | res = pkg_re.search(line) | 242 | res = pkg_re.search(value) |
174 | if res: | 243 | if res: |
175 | res = dep_re.findall(res.group(1)) | 244 | res = dep_re.findall(res.group(1)) |
176 | if res: | ||
177 | pcdeps.extend([x[0] for x in res]) | ||
178 | inherits.append('pkgconfig') | ||
179 | if line.lstrip().startswith('AM_GNU_GETTEXT'): | ||
180 | inherits.append('gettext') | ||
181 | elif 'AC_CHECK_PROG' in line or 'AC_PATH_PROG' in line: | ||
182 | res = progs_re.search(line) | ||
183 | if res: | 245 | if res: |
184 | for prog in shlex.split(res.group(1)): | 246 | pcdeps.extend([x[0] for x in res]) |
185 | prog = prog.split()[0] | 247 | inherits.append('pkgconfig') |
186 | progclass = progclassmap.get(prog, None) | 248 | elif keyword == 'AM_GNU_GETTEXT': |
187 | if progclass: | 249 | inherits.append('gettext') |
188 | inherits.append(progclass) | 250 | elif keyword == 'AC_CHECK_PROG' or keyword == 'AC_PATH_PROG': |
251 | res = progs_re.search(value) | ||
252 | if res: | ||
253 | for prog in shlex.split(res.group(1)): | ||
254 | prog = prog.split()[0] | ||
255 | progclass = progclassmap.get(prog, None) | ||
256 | if progclass: | ||
257 | inherits.append(progclass) | ||
258 | else: | ||
259 | progdep = progmap.get(prog, None) | ||
260 | if progdep: | ||
261 | deps.append(progdep) | ||
189 | else: | 262 | else: |
190 | progdep = progmap.get(prog, None) | 263 | if not prog.startswith('$'): |
191 | if progdep: | 264 | unmapped.append(prog) |
192 | deps.append(progdep) | 265 | elif keyword == 'AC_CHECK_LIB': |
193 | else: | 266 | res = lib_re.search(value) |
194 | if not prog.startswith('$'): | 267 | if res: |
195 | unmapped.append(prog) | 268 | lib = res.group(1) |
196 | elif 'AC_CHECK_LIB' in line: | 269 | libdep = recipelibmap.get(lib, None) |
197 | res = lib_re.search(line) | 270 | if libdep: |
271 | deps.append(libdep) | ||
272 | else: | ||
273 | if libdep is None: | ||
274 | if not lib.startswith('$'): | ||
275 | unmappedlibs.append(lib) | ||
276 | elif keyword == 'AC_PATH_X': | ||
277 | deps.append('libx11') | ||
278 | elif keyword == 'AC_INIT': | ||
279 | if extravalues is not None: | ||
280 | res = ac_init_re.match(value) | ||
198 | if res: | 281 | if res: |
199 | lib = res.group(1) | 282 | extravalues['PN'] = process_value(res.group(1)) |
200 | libdep = recipelibmap.get(lib, None) | 283 | pv = process_value(res.group(2)) |
201 | if libdep: | 284 | if validate_pv(pv): |
202 | deps.append(libdep) | 285 | extravalues['PV'] = pv |
203 | else: | 286 | elif keyword == 'AM_INIT_AUTOMAKE': |
204 | if libdep is None: | 287 | if extravalues is not None: |
205 | if not lib.startswith('$'): | 288 | if 'PN' not in extravalues: |
206 | unmappedlibs.append(lib) | 289 | res = am_init_re.match(value) |
207 | elif 'AC_PATH_X' in line: | 290 | if res: |
208 | deps.append('libx11') | 291 | if res.group(1) != 'AC_PACKAGE_NAME': |
292 | extravalues['PN'] = process_value(res.group(1)) | ||
293 | pv = process_value(res.group(2)) | ||
294 | if validate_pv(pv): | ||
295 | extravalues['PV'] = pv | ||
296 | elif keyword == 'define(': | ||
297 | res = define_re.match(value) | ||
298 | if res: | ||
299 | key = res.group(2).strip('[]') | ||
300 | value = process_value(res.group(3)) | ||
301 | if value is not None: | ||
302 | defines[key] = value | ||
303 | |||
304 | keywords = ['PKG_CHECK_MODULES', | ||
305 | 'AM_GNU_GETTEXT', | ||
306 | 'AC_CHECK_PROG', | ||
307 | 'AC_PATH_PROG', | ||
308 | 'AC_CHECK_LIB', | ||
309 | 'AC_PATH_X', | ||
310 | 'AC_INIT', | ||
311 | 'AM_INIT_AUTOMAKE', | ||
312 | 'define(', | ||
313 | ] | ||
314 | for srcfile in srcfiles: | ||
315 | nesting = 0 | ||
316 | in_keyword = '' | ||
317 | partial = '' | ||
318 | with open(srcfile, 'r') as f: | ||
319 | for line in f: | ||
320 | if in_keyword: | ||
321 | partial += ' ' + line.strip() | ||
322 | if partial.endswith('\\'): | ||
323 | partial = partial[:-1] | ||
324 | nesting = nesting + line.count('(') - line.count(')') | ||
325 | if nesting == 0: | ||
326 | process_macro(in_keyword, partial) | ||
327 | partial = '' | ||
328 | in_keyword = '' | ||
329 | else: | ||
330 | for keyword in keywords: | ||
331 | if keyword in line: | ||
332 | nesting = line.count('(') - line.count(')') | ||
333 | if nesting > 0: | ||
334 | partial = line.strip() | ||
335 | if partial.endswith('\\'): | ||
336 | partial = partial[:-1] | ||
337 | in_keyword = keyword | ||
338 | else: | ||
339 | process_macro(keyword, line.strip()) | ||
340 | break | ||
341 | |||
342 | if in_keyword: | ||
343 | process_macro(in_keyword, partial) | ||
344 | |||
345 | if extravalues: | ||
346 | for k,v in extravalues.items(): | ||
347 | if v: | ||
348 | if v.startswith('$') or v.startswith('@') or v.startswith('%'): | ||
349 | del extravalues[k] | ||
350 | else: | ||
351 | extravalues[k] = v.strip('"\'').rstrip('()') | ||
209 | 352 | ||
210 | if unmapped: | 353 | if unmapped: |
211 | outlines.append('# NOTE: the following prog dependencies are unknown, ignoring: %s' % ' '.join(unmapped)) | 354 | outlines.append('# NOTE: the following prog dependencies are unknown, ignoring: %s' % ' '.join(unmapped)) |
@@ -240,7 +383,7 @@ class AutotoolsRecipeHandler(RecipeHandler): | |||
240 | 383 | ||
241 | 384 | ||
242 | class MakefileRecipeHandler(RecipeHandler): | 385 | class MakefileRecipeHandler(RecipeHandler): |
243 | def process(self, srctree, classes, lines_before, lines_after, handled): | 386 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
244 | if 'buildsystem' in handled: | 387 | if 'buildsystem' in handled: |
245 | return False | 388 | return False |
246 | 389 | ||
@@ -307,6 +450,53 @@ class MakefileRecipeHandler(RecipeHandler): | |||
307 | self.genfunction(lines_after, 'do_install', ['# Specify install commands here']) | 450 | self.genfunction(lines_after, 'do_install', ['# Specify install commands here']) |
308 | 451 | ||
309 | 452 | ||
453 | class VersionFileRecipeHandler(RecipeHandler): | ||
454 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): | ||
455 | if 'PV' not in extravalues: | ||
456 | # Look for a VERSION or version file containing a single line consisting | ||
457 | # only of a version number | ||
458 | filelist = RecipeHandler.checkfiles(srctree, ['VERSION', 'version']) | ||
459 | version = None | ||
460 | for fileitem in filelist: | ||
461 | linecount = 0 | ||
462 | with open(fileitem, 'r') as f: | ||
463 | for line in f: | ||
464 | line = line.rstrip().strip('"\'') | ||
465 | linecount += 1 | ||
466 | if line: | ||
467 | if linecount > 1: | ||
468 | version = None | ||
469 | break | ||
470 | else: | ||
471 | if validate_pv(line): | ||
472 | version = line | ||
473 | if version: | ||
474 | extravalues['PV'] = version | ||
475 | break | ||
476 | |||
477 | |||
478 | class SpecFileRecipeHandler(RecipeHandler): | ||
479 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): | ||
480 | if 'PV' in extravalues and 'PN' in extravalues: | ||
481 | return | ||
482 | filelist = RecipeHandler.checkfiles(srctree, ['*.spec'], recursive=True) | ||
483 | pn = None | ||
484 | pv = None | ||
485 | for fileitem in filelist: | ||
486 | linecount = 0 | ||
487 | with open(fileitem, 'r') as f: | ||
488 | for line in f: | ||
489 | if line.startswith('Name:') and not pn: | ||
490 | pn = line.split(':')[1].strip() | ||
491 | if line.startswith('Version:') and not pv: | ||
492 | pv = line.split(':')[1].strip() | ||
493 | if pv or pn: | ||
494 | if pv and not 'PV' in extravalues and validate_pv(pv): | ||
495 | extravalues['PV'] = pv | ||
496 | if pn and not 'PN' in extravalues: | ||
497 | extravalues['PN'] = pn | ||
498 | break | ||
499 | |||
310 | def register_recipe_handlers(handlers): | 500 | def register_recipe_handlers(handlers): |
311 | # These are in a specific order so that the right one is detected first | 501 | # These are in a specific order so that the right one is detected first |
312 | handlers.append(CmakeRecipeHandler()) | 502 | handlers.append(CmakeRecipeHandler()) |
@@ -314,3 +504,5 @@ def register_recipe_handlers(handlers): | |||
314 | handlers.append(SconsRecipeHandler()) | 504 | handlers.append(SconsRecipeHandler()) |
315 | handlers.append(QmakeRecipeHandler()) | 505 | handlers.append(QmakeRecipeHandler()) |
316 | handlers.append(MakefileRecipeHandler()) | 506 | handlers.append(MakefileRecipeHandler()) |
507 | handlers.append((VersionFileRecipeHandler(), -1)) | ||
508 | handlers.append((SpecFileRecipeHandler(), -1)) | ||
diff --git a/scripts/lib/recipetool/create_buildsys_python.py b/scripts/lib/recipetool/create_buildsys_python.py index 266c423547..4d65c962b6 100644 --- a/scripts/lib/recipetool/create_buildsys_python.py +++ b/scripts/lib/recipetool/create_buildsys_python.py | |||
@@ -159,7 +159,7 @@ class PythonRecipeHandler(RecipeHandler): | |||
159 | def __init__(self): | 159 | def __init__(self): |
160 | pass | 160 | pass |
161 | 161 | ||
162 | def process(self, srctree, classes, lines_before, lines_after, handled): | 162 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
163 | if 'buildsystem' in handled: | 163 | if 'buildsystem' in handled: |
164 | return False | 164 | return False |
165 | 165 | ||