Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | # Recipe creation tool - create command build system handlers |
| 2 | # |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 3 | # Copyright (C) 2014-2016 Intel Corporation |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 4 | # |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame^] | 5 | # SPDX-License-Identifier: GPL-2.0-only |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 6 | # |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 7 | |
| 8 | import re |
| 9 | import logging |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 10 | import glob |
| 11 | from recipetool.create import RecipeHandler, validate_pv |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 12 | |
| 13 | logger = logging.getLogger('recipetool') |
| 14 | |
| 15 | tinfoil = None |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 16 | plugins = None |
| 17 | |
| 18 | def plugin_init(pluginlist): |
| 19 | # Take a reference to the list so we can use it later |
| 20 | global plugins |
| 21 | plugins = pluginlist |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 22 | |
| 23 | def tinfoil_init(instance): |
| 24 | global tinfoil |
| 25 | tinfoil = instance |
| 26 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 27 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 28 | class CmakeRecipeHandler(RecipeHandler): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 29 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 30 | if 'buildsystem' in handled: |
| 31 | return False |
| 32 | |
| 33 | if RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']): |
| 34 | classes.append('cmake') |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 35 | values = CmakeRecipeHandler.extract_cmake_deps(lines_before, srctree, extravalues) |
| 36 | classes.extend(values.pop('inherit', '').split()) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 37 | for var, value in values.items(): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 38 | lines_before.append('%s = "%s"' % (var, value)) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 39 | lines_after.append('# Specify any options you want to pass to cmake using EXTRA_OECMAKE:') |
| 40 | lines_after.append('EXTRA_OECMAKE = ""') |
| 41 | lines_after.append('') |
| 42 | handled.append('buildsystem') |
| 43 | return True |
| 44 | return False |
| 45 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 46 | @staticmethod |
| 47 | def extract_cmake_deps(outlines, srctree, extravalues, cmakelistsfile=None): |
| 48 | # Find all plugins that want to register handlers |
| 49 | logger.debug('Loading cmake handlers') |
| 50 | handlers = [] |
| 51 | for plugin in plugins: |
| 52 | if hasattr(plugin, 'register_cmake_handlers'): |
| 53 | plugin.register_cmake_handlers(handlers) |
| 54 | |
| 55 | values = {} |
| 56 | inherits = [] |
| 57 | |
| 58 | if cmakelistsfile: |
| 59 | srcfiles = [cmakelistsfile] |
| 60 | else: |
| 61 | srcfiles = RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']) |
| 62 | |
| 63 | # Note that some of these are non-standard, but probably better to |
| 64 | # be able to map them anyway if we see them |
| 65 | cmake_pkgmap = {'alsa': 'alsa-lib', |
| 66 | 'aspell': 'aspell', |
| 67 | 'atk': 'atk', |
| 68 | 'bison': 'bison-native', |
| 69 | 'boost': 'boost', |
| 70 | 'bzip2': 'bzip2', |
| 71 | 'cairo': 'cairo', |
| 72 | 'cups': 'cups', |
| 73 | 'curl': 'curl', |
| 74 | 'curses': 'ncurses', |
| 75 | 'cvs': 'cvs', |
| 76 | 'drm': 'libdrm', |
| 77 | 'dbus': 'dbus', |
| 78 | 'dbusglib': 'dbus-glib', |
| 79 | 'egl': 'virtual/egl', |
| 80 | 'expat': 'expat', |
| 81 | 'flex': 'flex-native', |
| 82 | 'fontconfig': 'fontconfig', |
| 83 | 'freetype': 'freetype', |
| 84 | 'gettext': '', |
| 85 | 'git': '', |
| 86 | 'gio': 'glib-2.0', |
| 87 | 'giounix': 'glib-2.0', |
| 88 | 'glew': 'glew', |
| 89 | 'glib': 'glib-2.0', |
| 90 | 'glib2': 'glib-2.0', |
| 91 | 'glu': 'libglu', |
| 92 | 'glut': 'freeglut', |
| 93 | 'gobject': 'glib-2.0', |
| 94 | 'gperf': 'gperf-native', |
| 95 | 'gnutls': 'gnutls', |
| 96 | 'gtk2': 'gtk+', |
| 97 | 'gtk3': 'gtk+3', |
| 98 | 'gtk': 'gtk+3', |
| 99 | 'harfbuzz': 'harfbuzz', |
| 100 | 'icu': 'icu', |
| 101 | 'intl': 'virtual/libintl', |
| 102 | 'jpeg': 'jpeg', |
| 103 | 'libarchive': 'libarchive', |
| 104 | 'libiconv': 'virtual/libiconv', |
| 105 | 'liblzma': 'xz', |
| 106 | 'libxml2': 'libxml2', |
| 107 | 'libxslt': 'libxslt', |
| 108 | 'opengl': 'virtual/libgl', |
| 109 | 'openmp': '', |
| 110 | 'openssl': 'openssl', |
| 111 | 'pango': 'pango', |
| 112 | 'perl': '', |
| 113 | 'perllibs': '', |
| 114 | 'pkgconfig': '', |
| 115 | 'png': 'libpng', |
| 116 | 'pthread': '', |
| 117 | 'pythoninterp': '', |
| 118 | 'pythonlibs': '', |
| 119 | 'ruby': 'ruby-native', |
| 120 | 'sdl': 'libsdl', |
| 121 | 'sdl2': 'libsdl2', |
| 122 | 'subversion': 'subversion-native', |
| 123 | 'swig': 'swig-native', |
| 124 | 'tcl': 'tcl-native', |
| 125 | 'threads': '', |
| 126 | 'tiff': 'tiff', |
| 127 | 'wget': 'wget', |
| 128 | 'x11': 'libx11', |
| 129 | 'xcb': 'libxcb', |
| 130 | 'xext': 'libxext', |
| 131 | 'xfixes': 'libxfixes', |
| 132 | 'zlib': 'zlib', |
| 133 | } |
| 134 | |
| 135 | pcdeps = [] |
| 136 | libdeps = [] |
| 137 | deps = [] |
| 138 | unmappedpkgs = [] |
| 139 | |
| 140 | proj_re = re.compile('project\s*\(([^)]*)\)', re.IGNORECASE) |
| 141 | pkgcm_re = re.compile('pkg_check_modules\s*\(\s*[a-zA-Z0-9-_]+\s*(REQUIRED)?\s+([^)\s]+)\s*\)', re.IGNORECASE) |
| 142 | pkgsm_re = re.compile('pkg_search_module\s*\(\s*[a-zA-Z0-9-_]+\s*(REQUIRED)?((\s+[^)\s]+)+)\s*\)', re.IGNORECASE) |
| 143 | findpackage_re = re.compile('find_package\s*\(\s*([a-zA-Z0-9-_]+)\s*.*', re.IGNORECASE) |
| 144 | findlibrary_re = re.compile('find_library\s*\(\s*[a-zA-Z0-9-_]+\s*(NAMES\s+)?([a-zA-Z0-9-_ ]+)\s*.*') |
| 145 | checklib_re = re.compile('check_library_exists\s*\(\s*([^\s)]+)\s*.*', re.IGNORECASE) |
| 146 | include_re = re.compile('include\s*\(\s*([^)\s]*)\s*\)', re.IGNORECASE) |
| 147 | subdir_re = re.compile('add_subdirectory\s*\(\s*([^)\s]*)\s*([^)\s]*)\s*\)', re.IGNORECASE) |
| 148 | dep_re = re.compile('([^ ><=]+)( *[<>=]+ *[^ ><=]+)?') |
| 149 | |
| 150 | def find_cmake_package(pkg): |
| 151 | RecipeHandler.load_devel_filemap(tinfoil.config_data) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 152 | for fn, pn in RecipeHandler.recipecmakefilemap.items(): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 153 | splitname = fn.split('/') |
| 154 | if len(splitname) > 1: |
| 155 | if splitname[0].lower().startswith(pkg.lower()): |
| 156 | if splitname[1] == '%s-config.cmake' % pkg.lower() or splitname[1] == '%sConfig.cmake' % pkg or splitname[1] == 'Find%s.cmake' % pkg: |
| 157 | return pn |
| 158 | return None |
| 159 | |
| 160 | def interpret_value(value): |
| 161 | return value.strip('"') |
| 162 | |
| 163 | def parse_cmake_file(fn, paths=None): |
| 164 | searchpaths = (paths or []) + [os.path.dirname(fn)] |
| 165 | logger.debug('Parsing file %s' % fn) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 166 | with open(fn, 'r', errors='surrogateescape') as f: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 167 | for line in f: |
| 168 | line = line.strip() |
| 169 | for handler in handlers: |
| 170 | if handler.process_line(srctree, fn, line, libdeps, pcdeps, deps, outlines, inherits, values): |
| 171 | continue |
| 172 | res = include_re.match(line) |
| 173 | if res: |
| 174 | includefn = bb.utils.which(':'.join(searchpaths), res.group(1)) |
| 175 | if includefn: |
| 176 | parse_cmake_file(includefn, searchpaths) |
| 177 | else: |
| 178 | logger.debug('Unable to recurse into include file %s' % res.group(1)) |
| 179 | continue |
| 180 | res = subdir_re.match(line) |
| 181 | if res: |
| 182 | subdirfn = os.path.join(os.path.dirname(fn), res.group(1), 'CMakeLists.txt') |
| 183 | if os.path.exists(subdirfn): |
| 184 | parse_cmake_file(subdirfn, searchpaths) |
| 185 | else: |
| 186 | logger.debug('Unable to recurse into subdirectory file %s' % subdirfn) |
| 187 | continue |
| 188 | res = proj_re.match(line) |
| 189 | if res: |
| 190 | extravalues['PN'] = interpret_value(res.group(1).split()[0]) |
| 191 | continue |
| 192 | res = pkgcm_re.match(line) |
| 193 | if res: |
| 194 | res = dep_re.findall(res.group(2)) |
| 195 | if res: |
| 196 | pcdeps.extend([interpret_value(x[0]) for x in res]) |
| 197 | inherits.append('pkgconfig') |
| 198 | continue |
| 199 | res = pkgsm_re.match(line) |
| 200 | if res: |
| 201 | res = dep_re.findall(res.group(2)) |
| 202 | if res: |
| 203 | # Note: appending a tuple here! |
| 204 | item = tuple((interpret_value(x[0]) for x in res)) |
| 205 | if len(item) == 1: |
| 206 | item = item[0] |
| 207 | pcdeps.append(item) |
| 208 | inherits.append('pkgconfig') |
| 209 | continue |
| 210 | res = findpackage_re.match(line) |
| 211 | if res: |
| 212 | origpkg = res.group(1) |
| 213 | pkg = interpret_value(origpkg) |
| 214 | found = False |
| 215 | for handler in handlers: |
| 216 | if handler.process_findpackage(srctree, fn, pkg, deps, outlines, inherits, values): |
| 217 | logger.debug('Mapped CMake package %s via handler %s' % (pkg, handler.__class__.__name__)) |
| 218 | found = True |
| 219 | break |
| 220 | if found: |
| 221 | continue |
| 222 | elif pkg == 'Gettext': |
| 223 | inherits.append('gettext') |
| 224 | elif pkg == 'Perl': |
| 225 | inherits.append('perlnative') |
| 226 | elif pkg == 'PkgConfig': |
| 227 | inherits.append('pkgconfig') |
| 228 | elif pkg == 'PythonInterp': |
| 229 | inherits.append('pythonnative') |
| 230 | elif pkg == 'PythonLibs': |
| 231 | inherits.append('python-dir') |
| 232 | else: |
| 233 | # Try to map via looking at installed CMake packages in pkgdata |
| 234 | dep = find_cmake_package(pkg) |
| 235 | if dep: |
| 236 | logger.debug('Mapped CMake package %s to recipe %s via pkgdata' % (pkg, dep)) |
| 237 | deps.append(dep) |
| 238 | else: |
| 239 | dep = cmake_pkgmap.get(pkg.lower(), None) |
| 240 | if dep: |
| 241 | logger.debug('Mapped CMake package %s to recipe %s via internal list' % (pkg, dep)) |
| 242 | deps.append(dep) |
| 243 | elif dep is None: |
| 244 | unmappedpkgs.append(origpkg) |
| 245 | continue |
| 246 | res = checklib_re.match(line) |
| 247 | if res: |
| 248 | lib = interpret_value(res.group(1)) |
| 249 | if not lib.startswith('$'): |
| 250 | libdeps.append(lib) |
| 251 | res = findlibrary_re.match(line) |
| 252 | if res: |
| 253 | libs = res.group(2).split() |
| 254 | for lib in libs: |
| 255 | if lib in ['HINTS', 'PATHS', 'PATH_SUFFIXES', 'DOC', 'NAMES_PER_DIR'] or lib.startswith(('NO_', 'CMAKE_', 'ONLY_CMAKE_')): |
| 256 | break |
| 257 | lib = interpret_value(lib) |
| 258 | if not lib.startswith('$'): |
| 259 | libdeps.append(lib) |
| 260 | if line.lower().startswith('useswig'): |
| 261 | deps.append('swig-native') |
| 262 | continue |
| 263 | |
| 264 | parse_cmake_file(srcfiles[0]) |
| 265 | |
| 266 | if unmappedpkgs: |
| 267 | outlines.append('# NOTE: unable to map the following CMake package dependencies: %s' % ' '.join(list(set(unmappedpkgs)))) |
| 268 | |
| 269 | RecipeHandler.handle_depends(libdeps, pcdeps, deps, outlines, values, tinfoil.config_data) |
| 270 | |
| 271 | for handler in handlers: |
| 272 | handler.post_process(srctree, libdeps, pcdeps, deps, outlines, inherits, values) |
| 273 | |
| 274 | if inherits: |
| 275 | values['inherit'] = ' '.join(list(set(inherits))) |
| 276 | |
| 277 | return values |
| 278 | |
| 279 | |
| 280 | class CmakeExtensionHandler(object): |
| 281 | '''Base class for CMake extension handlers''' |
| 282 | def process_line(self, srctree, fn, line, libdeps, pcdeps, deps, outlines, inherits, values): |
| 283 | ''' |
| 284 | Handle a line parsed out of an CMake file. |
| 285 | Return True if you've completely handled the passed in line, otherwise return False. |
| 286 | ''' |
| 287 | return False |
| 288 | |
| 289 | def process_findpackage(self, srctree, fn, pkg, deps, outlines, inherits, values): |
| 290 | ''' |
| 291 | Handle a find_package package parsed out of a CMake file. |
| 292 | Return True if you've completely handled the passed in package, otherwise return False. |
| 293 | ''' |
| 294 | return False |
| 295 | |
| 296 | def post_process(self, srctree, fn, pkg, deps, outlines, inherits, values): |
| 297 | ''' |
| 298 | Apply any desired post-processing on the output |
| 299 | ''' |
| 300 | return |
| 301 | |
| 302 | |
| 303 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 304 | class SconsRecipeHandler(RecipeHandler): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 305 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 306 | if 'buildsystem' in handled: |
| 307 | return False |
| 308 | |
| 309 | if RecipeHandler.checkfiles(srctree, ['SConstruct', 'Sconstruct', 'sconstruct']): |
| 310 | classes.append('scons') |
| 311 | lines_after.append('# Specify any options you want to pass to scons using EXTRA_OESCONS:') |
| 312 | lines_after.append('EXTRA_OESCONS = ""') |
| 313 | lines_after.append('') |
| 314 | handled.append('buildsystem') |
| 315 | return True |
| 316 | return False |
| 317 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 318 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 319 | class QmakeRecipeHandler(RecipeHandler): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 320 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 321 | if 'buildsystem' in handled: |
| 322 | return False |
| 323 | |
| 324 | if RecipeHandler.checkfiles(srctree, ['*.pro']): |
| 325 | classes.append('qmake2') |
| 326 | handled.append('buildsystem') |
| 327 | return True |
| 328 | return False |
| 329 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 330 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 331 | class AutotoolsRecipeHandler(RecipeHandler): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 332 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 333 | if 'buildsystem' in handled: |
| 334 | return False |
| 335 | |
| 336 | autoconf = False |
| 337 | if RecipeHandler.checkfiles(srctree, ['configure.ac', 'configure.in']): |
| 338 | autoconf = True |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 339 | values = AutotoolsRecipeHandler.extract_autotools_deps(lines_before, srctree, extravalues) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 340 | classes.extend(values.pop('inherit', '').split()) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 341 | for var, value in values.items(): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 342 | lines_before.append('%s = "%s"' % (var, value)) |
| 343 | else: |
| 344 | conffile = RecipeHandler.checkfiles(srctree, ['configure']) |
| 345 | if conffile: |
| 346 | # Check if this is just a pre-generated autoconf configure script |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 347 | with open(conffile[0], 'r', errors='surrogateescape') as f: |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 348 | for i in range(1, 10): |
| 349 | if 'Generated by GNU Autoconf' in f.readline(): |
| 350 | autoconf = True |
| 351 | break |
| 352 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 353 | if autoconf and not ('PV' in extravalues and 'PN' in extravalues): |
| 354 | # Last resort |
| 355 | conffile = RecipeHandler.checkfiles(srctree, ['configure']) |
| 356 | if conffile: |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 357 | with open(conffile[0], 'r', errors='surrogateescape') as f: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 358 | for line in f: |
| 359 | line = line.strip() |
| 360 | if line.startswith('VERSION=') or line.startswith('PACKAGE_VERSION='): |
| 361 | pv = line.split('=')[1].strip('"\'') |
| 362 | if pv and not 'PV' in extravalues and validate_pv(pv): |
| 363 | extravalues['PV'] = pv |
| 364 | elif line.startswith('PACKAGE_NAME=') or line.startswith('PACKAGE='): |
| 365 | pn = line.split('=')[1].strip('"\'') |
| 366 | if pn and not 'PN' in extravalues: |
| 367 | extravalues['PN'] = pn |
| 368 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 369 | if autoconf: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 370 | lines_before.append('') |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 371 | lines_before.append('# NOTE: if this software is not capable of being built in a separate build directory') |
| 372 | lines_before.append('# from the source, you should replace autotools with autotools-brokensep in the') |
| 373 | lines_before.append('# inherit line') |
| 374 | classes.append('autotools') |
| 375 | lines_after.append('# Specify any options you want to pass to the configure script using EXTRA_OECONF:') |
| 376 | lines_after.append('EXTRA_OECONF = ""') |
| 377 | lines_after.append('') |
| 378 | handled.append('buildsystem') |
| 379 | return True |
| 380 | |
| 381 | return False |
| 382 | |
| 383 | @staticmethod |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 384 | def extract_autotools_deps(outlines, srctree, extravalues=None, acfile=None): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 385 | import shlex |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 386 | |
| 387 | # Find all plugins that want to register handlers |
| 388 | logger.debug('Loading autotools handlers') |
| 389 | handlers = [] |
| 390 | for plugin in plugins: |
| 391 | if hasattr(plugin, 'register_autotools_handlers'): |
| 392 | plugin.register_autotools_handlers(handlers) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 393 | |
| 394 | values = {} |
| 395 | inherits = [] |
| 396 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 397 | # Hardcoded map, we also use a dynamic one based on what's in the sysroot |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 398 | progmap = {'flex': 'flex-native', |
| 399 | 'bison': 'bison-native', |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 400 | 'm4': 'm4-native', |
| 401 | 'tar': 'tar-native', |
| 402 | 'ar': 'binutils-native', |
| 403 | 'ranlib': 'binutils-native', |
| 404 | 'ld': 'binutils-native', |
| 405 | 'strip': 'binutils-native', |
| 406 | 'libtool': '', |
| 407 | 'autoconf': '', |
| 408 | 'autoheader': '', |
| 409 | 'automake': '', |
| 410 | 'uname': '', |
| 411 | 'rm': '', |
| 412 | 'cp': '', |
| 413 | 'mv': '', |
| 414 | 'find': '', |
| 415 | 'awk': '', |
| 416 | 'sed': '', |
| 417 | } |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 418 | progclassmap = {'gconftool-2': 'gconf', |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 419 | 'pkg-config': 'pkgconfig', |
| 420 | 'python': 'pythonnative', |
| 421 | 'python3': 'python3native', |
| 422 | 'perl': 'perlnative', |
| 423 | 'makeinfo': 'texinfo', |
| 424 | } |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 425 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 426 | pkg_re = re.compile('PKG_CHECK_MODULES\(\s*\[?[a-zA-Z0-9_]*\]?,\s*\[?([^,\]]*)\]?[),].*') |
| 427 | pkgce_re = re.compile('PKG_CHECK_EXISTS\(\s*\[?([^,\]]*)\]?[),].*') |
| 428 | lib_re = re.compile('AC_CHECK_LIB\(\s*\[?([^,\]]*)\]?,.*') |
| 429 | libx_re = re.compile('AX_CHECK_LIBRARY\(\s*\[?[^,\]]*\]?,\s*\[?([^,\]]*)\]?,\s*\[?([a-zA-Z0-9-]*)\]?,.*') |
| 430 | progs_re = re.compile('_PROGS?\(\s*\[?[a-zA-Z0-9_]*\]?,\s*\[?([^,\]]*)\]?[),].*') |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 431 | dep_re = re.compile('([^ ><=]+)( [<>=]+ [^ ><=]+)?') |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 432 | ac_init_re = re.compile('AC_INIT\(\s*([^,]+),\s*([^,]+)[,)].*') |
| 433 | am_init_re = re.compile('AM_INIT_AUTOMAKE\(\s*([^,]+),\s*([^,]+)[,)].*') |
| 434 | define_re = re.compile('\s*(m4_)?define\(\s*([^,]+),\s*([^,]+)\)') |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 435 | version_re = re.compile('([0-9.]+)') |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 436 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 437 | defines = {} |
| 438 | def subst_defines(value): |
| 439 | newvalue = value |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 440 | for define, defval in defines.items(): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 441 | newvalue = newvalue.replace(define, defval) |
| 442 | if newvalue != value: |
| 443 | return subst_defines(newvalue) |
| 444 | return value |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 445 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 446 | def process_value(value): |
| 447 | value = value.replace('[', '').replace(']', '') |
| 448 | if value.startswith('m4_esyscmd(') or value.startswith('m4_esyscmd_s('): |
| 449 | cmd = subst_defines(value[value.index('(')+1:-1]) |
| 450 | try: |
| 451 | if '|' in cmd: |
| 452 | cmd = 'set -o pipefail; ' + cmd |
| 453 | stdout, _ = bb.process.run(cmd, cwd=srctree, shell=True) |
| 454 | ret = stdout.rstrip() |
| 455 | except bb.process.ExecutionError as e: |
| 456 | ret = '' |
| 457 | elif value.startswith('m4_'): |
| 458 | return None |
| 459 | ret = subst_defines(value) |
| 460 | if ret: |
| 461 | ret = ret.strip('"\'') |
| 462 | return ret |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 463 | |
| 464 | # Since a configure.ac file is essentially a program, this is only ever going to be |
| 465 | # a hack unfortunately; but it ought to be enough of an approximation |
| 466 | if acfile: |
| 467 | srcfiles = [acfile] |
| 468 | else: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 469 | srcfiles = RecipeHandler.checkfiles(srctree, ['acinclude.m4', 'configure.ac', 'configure.in']) |
| 470 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 471 | pcdeps = [] |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 472 | libdeps = [] |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 473 | deps = [] |
| 474 | unmapped = [] |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 475 | |
| 476 | RecipeHandler.load_binmap(tinfoil.config_data) |
| 477 | |
| 478 | def process_macro(keyword, value): |
| 479 | for handler in handlers: |
| 480 | if handler.process_macro(srctree, keyword, value, process_value, libdeps, pcdeps, deps, outlines, inherits, values): |
| 481 | return |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 482 | logger.debug('Found keyword %s with value "%s"' % (keyword, value)) |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 483 | if keyword == 'PKG_CHECK_MODULES': |
| 484 | res = pkg_re.search(value) |
| 485 | if res: |
| 486 | res = dep_re.findall(res.group(1)) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 487 | if res: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 488 | pcdeps.extend([x[0] for x in res]) |
| 489 | inherits.append('pkgconfig') |
| 490 | elif keyword == 'PKG_CHECK_EXISTS': |
| 491 | res = pkgce_re.search(value) |
| 492 | if res: |
| 493 | res = dep_re.findall(res.group(1)) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 494 | if res: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 495 | pcdeps.extend([x[0] for x in res]) |
| 496 | inherits.append('pkgconfig') |
| 497 | elif keyword in ('AM_GNU_GETTEXT', 'AM_GLIB_GNU_GETTEXT', 'GETTEXT_PACKAGE'): |
| 498 | inherits.append('gettext') |
| 499 | elif keyword in ('AC_PROG_INTLTOOL', 'IT_PROG_INTLTOOL'): |
| 500 | deps.append('intltool-native') |
| 501 | elif keyword == 'AM_PATH_GLIB_2_0': |
| 502 | deps.append('glib-2.0') |
| 503 | elif keyword in ('AC_CHECK_PROG', 'AC_PATH_PROG', 'AX_WITH_PROG'): |
| 504 | res = progs_re.search(value) |
| 505 | if res: |
| 506 | for prog in shlex.split(res.group(1)): |
| 507 | prog = prog.split()[0] |
| 508 | for handler in handlers: |
| 509 | if handler.process_prog(srctree, keyword, value, prog, deps, outlines, inherits, values): |
| 510 | return |
| 511 | progclass = progclassmap.get(prog, None) |
| 512 | if progclass: |
| 513 | inherits.append(progclass) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 514 | else: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 515 | progdep = RecipeHandler.recipebinmap.get(prog, None) |
| 516 | if not progdep: |
| 517 | progdep = progmap.get(prog, None) |
| 518 | if progdep: |
| 519 | deps.append(progdep) |
| 520 | elif progdep is None: |
| 521 | if not prog.startswith('$'): |
| 522 | unmapped.append(prog) |
| 523 | elif keyword == 'AC_CHECK_LIB': |
| 524 | res = lib_re.search(value) |
| 525 | if res: |
| 526 | lib = res.group(1) |
| 527 | if not lib.startswith('$'): |
| 528 | libdeps.append(lib) |
| 529 | elif keyword == 'AX_CHECK_LIBRARY': |
| 530 | res = libx_re.search(value) |
| 531 | if res: |
| 532 | lib = res.group(2) |
| 533 | if not lib.startswith('$'): |
| 534 | header = res.group(1) |
| 535 | libdeps.append((lib, header)) |
| 536 | elif keyword == 'AC_PATH_X': |
| 537 | deps.append('libx11') |
| 538 | elif keyword in ('AX_BOOST', 'BOOST_REQUIRE'): |
| 539 | deps.append('boost') |
| 540 | elif keyword in ('AC_PROG_LEX', 'AM_PROG_LEX', 'AX_PROG_FLEX'): |
| 541 | deps.append('flex-native') |
| 542 | elif keyword in ('AC_PROG_YACC', 'AX_PROG_BISON'): |
| 543 | deps.append('bison-native') |
| 544 | elif keyword == 'AX_CHECK_ZLIB': |
| 545 | deps.append('zlib') |
| 546 | elif keyword in ('AX_CHECK_OPENSSL', 'AX_LIB_CRYPTO'): |
| 547 | deps.append('openssl') |
| 548 | elif keyword == 'AX_LIB_CURL': |
| 549 | deps.append('curl') |
| 550 | elif keyword == 'AX_LIB_BEECRYPT': |
| 551 | deps.append('beecrypt') |
| 552 | elif keyword == 'AX_LIB_EXPAT': |
| 553 | deps.append('expat') |
| 554 | elif keyword == 'AX_LIB_GCRYPT': |
| 555 | deps.append('libgcrypt') |
| 556 | elif keyword == 'AX_LIB_NETTLE': |
| 557 | deps.append('nettle') |
| 558 | elif keyword == 'AX_LIB_READLINE': |
| 559 | deps.append('readline') |
| 560 | elif keyword == 'AX_LIB_SQLITE3': |
| 561 | deps.append('sqlite3') |
| 562 | elif keyword == 'AX_LIB_TAGLIB': |
| 563 | deps.append('taglib') |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 564 | elif keyword in ['AX_PKG_SWIG', 'AC_PROG_SWIG']: |
| 565 | deps.append('swig-native') |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 566 | elif keyword == 'AX_PROG_XSLTPROC': |
| 567 | deps.append('libxslt-native') |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 568 | elif keyword in ['AC_PYTHON_DEVEL', 'AX_PYTHON_DEVEL', 'AM_PATH_PYTHON']: |
| 569 | pythonclass = 'pythonnative' |
| 570 | res = version_re.search(value) |
| 571 | if res: |
| 572 | if res.group(1).startswith('3'): |
| 573 | pythonclass = 'python3native' |
| 574 | # Avoid replacing python3native with pythonnative |
| 575 | if not pythonclass in inherits and not 'python3native' in inherits: |
| 576 | if 'pythonnative' in inherits: |
| 577 | inherits.remove('pythonnative') |
| 578 | inherits.append(pythonclass) |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 579 | elif keyword == 'AX_WITH_CURSES': |
| 580 | deps.append('ncurses') |
| 581 | elif keyword == 'AX_PATH_BDB': |
| 582 | deps.append('db') |
| 583 | elif keyword == 'AX_PATH_LIB_PCRE': |
| 584 | deps.append('libpcre') |
| 585 | elif keyword == 'AC_INIT': |
| 586 | if extravalues is not None: |
| 587 | res = ac_init_re.match(value) |
| 588 | if res: |
| 589 | extravalues['PN'] = process_value(res.group(1)) |
| 590 | pv = process_value(res.group(2)) |
| 591 | if validate_pv(pv): |
| 592 | extravalues['PV'] = pv |
| 593 | elif keyword == 'AM_INIT_AUTOMAKE': |
| 594 | if extravalues is not None: |
| 595 | if 'PN' not in extravalues: |
| 596 | res = am_init_re.match(value) |
| 597 | if res: |
| 598 | if res.group(1) != 'AC_PACKAGE_NAME': |
| 599 | extravalues['PN'] = process_value(res.group(1)) |
| 600 | pv = process_value(res.group(2)) |
| 601 | if validate_pv(pv): |
| 602 | extravalues['PV'] = pv |
| 603 | elif keyword == 'define(': |
| 604 | res = define_re.match(value) |
| 605 | if res: |
| 606 | key = res.group(2).strip('[]') |
| 607 | value = process_value(res.group(3)) |
| 608 | if value is not None: |
| 609 | defines[key] = value |
| 610 | |
| 611 | keywords = ['PKG_CHECK_MODULES', |
| 612 | 'PKG_CHECK_EXISTS', |
| 613 | 'AM_GNU_GETTEXT', |
| 614 | 'AM_GLIB_GNU_GETTEXT', |
| 615 | 'GETTEXT_PACKAGE', |
| 616 | 'AC_PROG_INTLTOOL', |
| 617 | 'IT_PROG_INTLTOOL', |
| 618 | 'AM_PATH_GLIB_2_0', |
| 619 | 'AC_CHECK_PROG', |
| 620 | 'AC_PATH_PROG', |
| 621 | 'AX_WITH_PROG', |
| 622 | 'AC_CHECK_LIB', |
| 623 | 'AX_CHECK_LIBRARY', |
| 624 | 'AC_PATH_X', |
| 625 | 'AX_BOOST', |
| 626 | 'BOOST_REQUIRE', |
| 627 | 'AC_PROG_LEX', |
| 628 | 'AM_PROG_LEX', |
| 629 | 'AX_PROG_FLEX', |
| 630 | 'AC_PROG_YACC', |
| 631 | 'AX_PROG_BISON', |
| 632 | 'AX_CHECK_ZLIB', |
| 633 | 'AX_CHECK_OPENSSL', |
| 634 | 'AX_LIB_CRYPTO', |
| 635 | 'AX_LIB_CURL', |
| 636 | 'AX_LIB_BEECRYPT', |
| 637 | 'AX_LIB_EXPAT', |
| 638 | 'AX_LIB_GCRYPT', |
| 639 | 'AX_LIB_NETTLE', |
| 640 | 'AX_LIB_READLINE' |
| 641 | 'AX_LIB_SQLITE3', |
| 642 | 'AX_LIB_TAGLIB', |
| 643 | 'AX_PKG_SWIG', |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 644 | 'AC_PROG_SWIG', |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 645 | 'AX_PROG_XSLTPROC', |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 646 | 'AC_PYTHON_DEVEL', |
| 647 | 'AX_PYTHON_DEVEL', |
| 648 | 'AM_PATH_PYTHON', |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 649 | 'AX_WITH_CURSES', |
| 650 | 'AX_PATH_BDB', |
| 651 | 'AX_PATH_LIB_PCRE', |
| 652 | 'AC_INIT', |
| 653 | 'AM_INIT_AUTOMAKE', |
| 654 | 'define(', |
| 655 | ] |
| 656 | |
| 657 | for handler in handlers: |
| 658 | handler.extend_keywords(keywords) |
| 659 | |
| 660 | for srcfile in srcfiles: |
| 661 | nesting = 0 |
| 662 | in_keyword = '' |
| 663 | partial = '' |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 664 | with open(srcfile, 'r', errors='surrogateescape') as f: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 665 | for line in f: |
| 666 | if in_keyword: |
| 667 | partial += ' ' + line.strip() |
| 668 | if partial.endswith('\\'): |
| 669 | partial = partial[:-1] |
| 670 | nesting = nesting + line.count('(') - line.count(')') |
| 671 | if nesting == 0: |
| 672 | process_macro(in_keyword, partial) |
| 673 | partial = '' |
| 674 | in_keyword = '' |
| 675 | else: |
| 676 | for keyword in keywords: |
| 677 | if keyword in line: |
| 678 | nesting = line.count('(') - line.count(')') |
| 679 | if nesting > 0: |
| 680 | partial = line.strip() |
| 681 | if partial.endswith('\\'): |
| 682 | partial = partial[:-1] |
| 683 | in_keyword = keyword |
| 684 | else: |
| 685 | process_macro(keyword, line.strip()) |
| 686 | break |
| 687 | |
| 688 | if in_keyword: |
| 689 | process_macro(in_keyword, partial) |
| 690 | |
| 691 | if extravalues: |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 692 | for k,v in list(extravalues.items()): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 693 | if v: |
| 694 | if v.startswith('$') or v.startswith('@') or v.startswith('%'): |
| 695 | del extravalues[k] |
| 696 | else: |
| 697 | extravalues[k] = v.strip('"\'').rstrip('()') |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 698 | |
| 699 | if unmapped: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 700 | outlines.append('# NOTE: the following prog dependencies are unknown, ignoring: %s' % ' '.join(list(set(unmapped)))) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 701 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 702 | RecipeHandler.handle_depends(libdeps, pcdeps, deps, outlines, values, tinfoil.config_data) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 703 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 704 | for handler in handlers: |
| 705 | handler.post_process(srctree, libdeps, pcdeps, deps, outlines, inherits, values) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 706 | |
| 707 | if inherits: |
| 708 | values['inherit'] = ' '.join(list(set(inherits))) |
| 709 | |
| 710 | return values |
| 711 | |
| 712 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 713 | class AutotoolsExtensionHandler(object): |
| 714 | '''Base class for Autotools extension handlers''' |
| 715 | def process_macro(self, srctree, keyword, value, process_value, libdeps, pcdeps, deps, outlines, inherits, values): |
| 716 | ''' |
| 717 | Handle a macro parsed out of an autotools file. Note that if you want this to be called |
| 718 | for any macro other than the ones AutotoolsRecipeHandler already looks for, you'll need |
| 719 | to add it to the keywords list in extend_keywords(). |
| 720 | Return True if you've completely handled the passed in macro, otherwise return False. |
| 721 | ''' |
| 722 | return False |
| 723 | |
| 724 | def extend_keywords(self, keywords): |
| 725 | '''Adds keywords to be recognised by the parser (so that you get a call to process_macro)''' |
| 726 | return |
| 727 | |
| 728 | def process_prog(self, srctree, keyword, value, prog, deps, outlines, inherits, values): |
| 729 | ''' |
| 730 | Handle an AC_PATH_PROG, AC_CHECK_PROG etc. line |
| 731 | Return True if you've completely handled the passed in macro, otherwise return False. |
| 732 | ''' |
| 733 | return False |
| 734 | |
| 735 | def post_process(self, srctree, fn, pkg, deps, outlines, inherits, values): |
| 736 | ''' |
| 737 | Apply any desired post-processing on the output |
| 738 | ''' |
| 739 | return |
| 740 | |
| 741 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 742 | class MakefileRecipeHandler(RecipeHandler): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 743 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 744 | if 'buildsystem' in handled: |
| 745 | return False |
| 746 | |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 747 | makefile = RecipeHandler.checkfiles(srctree, ['Makefile', 'makefile', 'GNUmakefile']) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 748 | if makefile: |
| 749 | lines_after.append('# NOTE: this is a Makefile-only piece of software, so we cannot generate much of the') |
| 750 | lines_after.append('# recipe automatically - you will need to examine the Makefile yourself and ensure') |
| 751 | lines_after.append('# that the appropriate arguments are passed in.') |
| 752 | lines_after.append('') |
| 753 | |
| 754 | scanfile = os.path.join(srctree, 'configure.scan') |
| 755 | skipscan = False |
| 756 | try: |
| 757 | stdout, stderr = bb.process.run('autoscan', cwd=srctree, shell=True) |
| 758 | except bb.process.ExecutionError as e: |
| 759 | skipscan = True |
| 760 | if scanfile and os.path.exists(scanfile): |
| 761 | values = AutotoolsRecipeHandler.extract_autotools_deps(lines_before, srctree, acfile=scanfile) |
| 762 | classes.extend(values.pop('inherit', '').split()) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 763 | for var, value in values.items(): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 764 | if var == 'DEPENDS': |
| 765 | lines_before.append('# NOTE: some of these dependencies may be optional, check the Makefile and/or upstream documentation') |
| 766 | lines_before.append('%s = "%s"' % (var, value)) |
| 767 | lines_before.append('') |
| 768 | for f in ['configure.scan', 'autoscan.log']: |
| 769 | fp = os.path.join(srctree, f) |
| 770 | if os.path.exists(fp): |
| 771 | os.remove(fp) |
| 772 | |
| 773 | self.genfunction(lines_after, 'do_configure', ['# Specify any needed configure commands here']) |
| 774 | |
| 775 | func = [] |
| 776 | func.append('# You will almost certainly need to add additional arguments here') |
| 777 | func.append('oe_runmake') |
| 778 | self.genfunction(lines_after, 'do_compile', func) |
| 779 | |
| 780 | installtarget = True |
| 781 | try: |
Patrick Williams | f1e5d69 | 2016-03-30 15:21:19 -0500 | [diff] [blame] | 782 | stdout, stderr = bb.process.run('make -n install', cwd=srctree, shell=True) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 783 | except bb.process.ExecutionError as e: |
| 784 | if e.exitcode != 1: |
| 785 | installtarget = False |
| 786 | func = [] |
| 787 | if installtarget: |
| 788 | func.append('# This is a guess; additional arguments may be required') |
| 789 | makeargs = '' |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 790 | with open(makefile[0], 'r', errors='surrogateescape') as f: |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 791 | for i in range(1, 100): |
| 792 | if 'DESTDIR' in f.readline(): |
| 793 | makeargs += " 'DESTDIR=${D}'" |
| 794 | break |
| 795 | func.append('oe_runmake install%s' % makeargs) |
| 796 | else: |
| 797 | func.append('# NOTE: unable to determine what to put here - there is a Makefile but no') |
| 798 | func.append('# target named "install", so you will need to define this yourself') |
| 799 | self.genfunction(lines_after, 'do_install', func) |
| 800 | |
| 801 | handled.append('buildsystem') |
| 802 | else: |
| 803 | lines_after.append('# NOTE: no Makefile found, unable to determine what needs to be done') |
| 804 | lines_after.append('') |
| 805 | self.genfunction(lines_after, 'do_configure', ['# Specify any needed configure commands here']) |
| 806 | self.genfunction(lines_after, 'do_compile', ['# Specify compilation commands here']) |
| 807 | self.genfunction(lines_after, 'do_install', ['# Specify install commands here']) |
| 808 | |
| 809 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 810 | class VersionFileRecipeHandler(RecipeHandler): |
| 811 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
| 812 | if 'PV' not in extravalues: |
| 813 | # Look for a VERSION or version file containing a single line consisting |
| 814 | # only of a version number |
| 815 | filelist = RecipeHandler.checkfiles(srctree, ['VERSION', 'version']) |
| 816 | version = None |
| 817 | for fileitem in filelist: |
| 818 | linecount = 0 |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 819 | with open(fileitem, 'r', errors='surrogateescape') as f: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 820 | for line in f: |
| 821 | line = line.rstrip().strip('"\'') |
| 822 | linecount += 1 |
| 823 | if line: |
| 824 | if linecount > 1: |
| 825 | version = None |
| 826 | break |
| 827 | else: |
| 828 | if validate_pv(line): |
| 829 | version = line |
| 830 | if version: |
| 831 | extravalues['PV'] = version |
| 832 | break |
| 833 | |
| 834 | |
| 835 | class SpecFileRecipeHandler(RecipeHandler): |
| 836 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
| 837 | if 'PV' in extravalues and 'PN' in extravalues: |
| 838 | return |
| 839 | filelist = RecipeHandler.checkfiles(srctree, ['*.spec'], recursive=True) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 840 | valuemap = {'Name': 'PN', |
| 841 | 'Version': 'PV', |
| 842 | 'Summary': 'SUMMARY', |
| 843 | 'Url': 'HOMEPAGE', |
| 844 | 'License': 'LICENSE'} |
| 845 | foundvalues = {} |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 846 | for fileitem in filelist: |
| 847 | linecount = 0 |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 848 | with open(fileitem, 'r', errors='surrogateescape') as f: |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 849 | for line in f: |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 850 | for value, varname in valuemap.items(): |
| 851 | if line.startswith(value + ':') and not varname in foundvalues: |
| 852 | foundvalues[varname] = line.split(':', 1)[1].strip() |
| 853 | break |
| 854 | if len(foundvalues) == len(valuemap): |
| 855 | break |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 856 | # Drop values containing unexpanded RPM macros |
| 857 | for k in list(foundvalues.keys()): |
| 858 | if '%' in foundvalues[k]: |
| 859 | del foundvalues[k] |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 860 | if 'PV' in foundvalues: |
| 861 | if not validate_pv(foundvalues['PV']): |
| 862 | del foundvalues['PV'] |
| 863 | license = foundvalues.pop('LICENSE', None) |
| 864 | if license: |
| 865 | liccomment = '# NOTE: spec file indicates the license may be "%s"' % license |
| 866 | for i, line in enumerate(lines_before): |
| 867 | if line.startswith('LICENSE ='): |
| 868 | lines_before.insert(i, liccomment) |
| 869 | break |
| 870 | else: |
| 871 | lines_before.append(liccomment) |
| 872 | extravalues.update(foundvalues) |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 873 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 874 | def register_recipe_handlers(handlers): |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 875 | # Set priorities with some gaps so that other plugins can insert |
| 876 | # their own handlers (so avoid changing these numbers) |
| 877 | handlers.append((CmakeRecipeHandler(), 50)) |
| 878 | handlers.append((AutotoolsRecipeHandler(), 40)) |
| 879 | handlers.append((SconsRecipeHandler(), 30)) |
| 880 | handlers.append((QmakeRecipeHandler(), 20)) |
| 881 | handlers.append((MakefileRecipeHandler(), 10)) |
| 882 | handlers.append((VersionFileRecipeHandler(), -1)) |
| 883 | handlers.append((SpecFileRecipeHandler(), -1)) |