Package: oelint-adv
oelint-advAdvanced oelintPurposeBased on theOpenEmbedded Styleguideand work done byoe-stylize-toolthis module offers a (nearly) complete linter for bitbake-recipes.The tool should help anyone working with YOCTO/OpenEmbedded to write more clean, less 'magical' recipes, without the need to know all the internals of your used poky/OpenEmbedded version.It could also be used as part of a CI to avoid hard to debug issues slipping to your code base - be sure to checkoutrulefilefor that use case.As every linter this tool is sometimes extra picky, but for the good of it, not just to bug people.
Especially for novice users it might be a help to avoid the most common pitfalls of bitbake recipes.The tool does handle includes/requires automatically, so you don't have to pass them via CLI.NOTE: .bbappend-files have to be passed via CLI - these are NOT gathered automatically.InstallWith pip (recommended)pip3installoelint_advfrom sourcegitclonehttps://github.com/priv-kweihmann/oelint-advcdoelint-adv
python3setup.pyinstall# might require sudo/root permissionsNOTEif you install from source, you'll have to provide all matching
required python libraries on your own. Seerequirements.txtfor detailsUsageusage:oelint-adv[-h][--suppressSUPPRESS][--outputOUTPUT][--fix][--nobackup][--addrulesADDRULES[ADDRULES...]][--customrulesCUSTOMRULES[CUSTOMRULES...]][--rulefileRULEFILE][--jobsJOBS][--color][--quiet][--noinfo][--nowarn][--relpaths][--noid][--messageformatMESSAGEFORMAT][--constantmodsCONSTANTMODS[CONSTANTMODS...]][--print-rulefile][--exit-zero][--version][files...]AdvancedOELint-CheckbitbakerecipesagainstOECorestyleguide

positionalarguments:filesFiletoparse

options:-h,--helpshowthishelpmessageandexit--suppressSUPPRESSRulestosuppress--outputOUTPUTWheretoflushthefindings(default:stderr)--fixAutomaticallytrytofixtheissues--nobackupDon't create backup file when auto fixing--addrules ADDRULES [ADDRULES ...]Additional non-default rulessets to add--customrules CUSTOMRULES [CUSTOMRULES ...]Additional directories to parse for rulessets--rulefile RULEFILE   Rulefile--jobs JOBS           Number of jobs to run (default all cores)--color               Add color to the output based on the severity--quiet               Print findings only--noinfo              Don'tprintinformationlevelfindings--nowarnDon't print warning level findings--relpaths            Show relative paths instead of absolute paths in results--noid                Don'tshowtheerror-IDintheoutput--messageformatMESSAGEFORMATFormatofmessageoutput--constantmodsCONSTANTMODS[CONSTANTMODS...]Modificationstotheconstantdb.prefixwith:+-toaddtoDB,--toremovefromDB,None-tooverrideDB--print-rulefilePrintloadedrulesasarulefileandexit--releaseRunagainstaspecificYoctorelease(default:latest)--exit-zeroAlwaysreturna0(non-error)statuscode,eveniflinterrorsarefound--versionshowprogram'sversionnumberandexitOutputWill be [file]:[line]:[severity]:[id]:[message].
To change the default message format, please seeOutput message formatsection.Example:/disk/meta-some/cppcheck-native/cppcheck.inc:26:error:oelint.task.nomkdir:'mkdir'shallnotbeusedindo_install.Use'install'/disk/meta-some/cppcheck-native/cppcheck-native_1.87.bb:0:error:oelint.var.mandatoryvar.SECTION:Variable'SECTION'shouldbeset/disk/meta-some/cppcheck-native/cppcheck.inc:1:warning:oelint.vars.summary80chars:'SUMMARY'shouldnotbelongerthan80characters
/disk/meta-some/cppcheck-native/cppcheck.inc:4:warning:oelint.vars.homepageprefix:'HOMEPAGE'shouldstartwith'http://'or'https://'/disk/meta-some/cppcheck-native/cppcheck.inc:28:warning:oelint.spaces.lineend:Lineshallnotendwithaspace
/disk/meta-some/cppcheck-native/cppcheck-native_1.87.bb:0:error:oelint.var.mandatoryvar.AUTHOR:Variable'AUTHOR'shouldbeset/disk/meta-some/cppcheck-native/cppcheck.inc:26:error:oelint.task.nocopy:'cp'shallnotbeusedindo_install.Use'install'/disk/meta-some/cppcheck-native/cppcheck.inc:12:warning:oelint.var.order.DEPENDS:'DEPENDS'shouldbeplacedbefore'inherit'Apply automatic fixingSome of the rules are capable of fixing the issues found automatically.
This will be done if you pass--fixas a startup parameter.As long as you don't pass--nobackupa backup copy (filename + .bak) will be created for all files fixed.Available rulesRules marked with[F]are able to perform automatic fixing
Rules marked with[S]can have multiple sub-IDsoelint.append.protvars - Variables that shouldn't be set in a bbappend[S]oelint.bbclass.underscores - bbclass filenames shall not contain dashesoelint.exportfunction.dash - EXPORT_FUNCTIONS shall not contain dashesoelint.file.inactiveupstreamdetails - Patches with Upstream-Status: Inactive-Upstream require more detailsoelint.file.inappropriatemsg - Patches with Upstream-Status: Inappropriate should provide a valid reasoningoelint.file.includenotfound - File to be included not foundoelint.file.includerelpath - Require should be used instead of includeoelint.file.inlinesuppress_na - A not applicable inline suppression has been foundoelint.file.nospaces - Path to file should not contain spacesoelint.file.patchsignedoff - Patches should contain a Signed-Of-By entryoelint.file.requireinclude - Require should be used instead of includeoelint.file.requirenotfound - File to be required not foundoelint.file.underscores - Checks the correct usage of underscores in filenameoelint.file.upstreamstatus - Patches should contain a Upstream-Status entryoelint.func.specific - Function is specific to an unknown identifieroelint.newline.consecutive - Consecutive blank lines should be avoided[F]oelint.newline.eof - File shall end on a newline[F]oelint.spaces.emptyline - Empty line should not contain spaces or tabs[F]oelint.spaces.linebeginning - No space at a line beginning[F]oelint.spaces.linecont - Safe line continuation[F]oelint.spaces.lineend - No spaces at line end[F]oelint.tabs.notabs - No tabs allowed[F]oelint.task.addnotaskbody - Task added by addtask cannot be foundoelint.task.customorder - order of custom tasks added via addtaskoelint.task.dash - Functions and related statements shall not contain dashesoelint.task.docstrings - Custom tasks should have docstringsoelint.task.heredocs - Usage of heredocs should be avoided. Use files insteadoelint.task.multifragments - Multiple fragments of the same function in the same file should be mergedoelint.task.noanonpython - Avoid anonymous python functionsoelint.task.nocopy - No cp usage in do_installoelint.task.nomkdir - No mkdir usage in do_installoelint.task.nopythonprefix - Tasks containing shell code should NOT be prefixed with 'python' in function headeroelint.task.order - Order of tasks[S]oelint.task.pythonprefix - Tasks containing python code should be prefixed with 'python' in function headeroelint.var.addpylib - addpylib is only valid in .conf filesoelint.var.bbclassextend - Use BBCLASSEXTEND when possibleoelint.var.filesoverride - FILES:(FILES_) variables should not be overriddenoelint.var.improperinherit - Warn about improperly named inheritsoelint.var.inherit - Check the correct usage of inherit and inherit_defer (scarthgap+)oelint.var.inheritdevtool - inherit_defer is recommended for native and nativesdk class[S](scarthgap+)oelint.var.licenseremotefile - License shall be a file in remote source not a local fileoelint.var.licensesdpx - Check for correct SPDX syntax in licensesoelint.var.mandatoryvar - Check for mandatory variables[S]oelint.var.multiinclude - Warn on including the same file more than onceoelint.var.multiinherit - Warn on inherit the same file more than onceoelint.var.nativefilename - Native only recipes should be named -nativeoelint.var.nativesdkfilename - NativeSDK only recipes should be named nativesdk-oelint.var.order - Variable order[S]oelint.var.override - Check if include/append is overriding a variableoelint.var.rootfspostcmd - ROOTFS_POSTPROCESS_COMMAND should not have trailing blanksoelint.var.srcuriwildcard - 'SRC_URI' should not contain any wildcardsoelint.var.suggestedvar - Notice on suggested variables[S]oelint.vars.appendop - Use ':append(_append)' instead of ' += 'oelint.vars.autorev - The usage of 'AUTOREV' for SRCREV leads to not reproducible buildsoelint.vars.bbvars - Variables that shouldn't be altered in recipe scope[S]oelint.vars.bugtrackerisurl - BUGTRACKER should be an URLoelint.vars.dependsappend - DEPENDS should only be appended, not overwrittenoelint.vars.dependsclass - DEPENDS should use the correct class variantsoelint.vars.dependsordered - RDEPENDS entries should be ordered alphabeticallyoelint.vars.descriptionsame - 'DESCRIPTION' is the same a 'SUMMARY' - it can be removed thenoelint.vars.descriptiontoobrief - 'DESCRIPTION' is the shorter than 'SUMMARY'oelint.vars.doublemodify - Multiple modifiers of append/prepend/remove/+= found in one operationoelint.vars.downloadfilename - Fetcher does create a download artifact without 'PV' in the filenameoelint.vars.duplicate - No duplicates in DEPENDS and RDEPENDSoelint.vars.dusageinpkgfuncs - use $D instead of ${D} in pkg functions[F]oelint.vars.fileextrapaths - 'FILESEXTRAPATHS' shouldn't be used in a bb fileoelint.vars.fileextrapathsop - 'FILESEXTRAPATHS' should only be used in combination with ' := 'oelint.vars.filessetting - unnecessary FILES settingsoelint.vars.homepageping - 'HOMEPAGE' isn't reachableoelint.vars.homepageprefix - HOMEPAGE should begin with https:// or http://oelint.vars.inconspaces - Inconsistent use of spaces on append operationoelint.vars.insaneskip - INSANE_SKIP should be avoided at any costoelint.vars.licfileprefix - Unnecessary prefix to LIC_FILES_CHKSUM detected[F]oelint.vars.listappend - Proper append/prepend to lists[F]oelint.vars.mispell - Possible typo detectedoelint.vars.mispell.unknown - Variable is not known from CONSTANTS, typo is unlikelyoelint.vars.multilineident - On a multiline assignment, line indent is desirableoelint.vars.notneededspace - Space at the beginning of the var is not needed[F]oelint.vars.notrailingslash - Variable shall not end on a slashoelint.vars.overrideappend - Check correct order of append/prepend on variables with override syntaxoelint.vars.pathhardcode - Warn about the usage of hardcoded paths[S]oelint.vars.pbpusage - ${BP} should be used instead of ${P}[F]oelint.vars.pkgspecific - Variable is package-specific, but isn't set in that way[S]oelint.vars.pnbpnusage - ${BPN} should be used instead of ${PN}[F]oelint.vars.pnusagediscouraged - Variable shouldn't contain ${PN} or ${BPN}oelint.vars.pythonpnusage - python3 should be used instead of ${PYTHON_PN}[F](scarthgap+)oelint.vars.sectionlowercase - SECTION should be lowercase only[F]oelint.vars.spacesassignment - ' = ' should be correct variable assignmentoelint.vars.specific - Variable is specific to an unknown identifieroelint.vars.srcuriappend - Use SRC_URI:append(SRC_URI_append) otherwise this will override weak defaults by inheritoelint.vars.srcurichecksum - If SRC_URI has URLs pointing single file that is not from VCS, then checksusm is requiredoelint.vars.srcuridomains - Recipe is pulling from different domains, this will likely cause issuesoelint.vars.srcurifile - First item of SRC_URI should not be a file:// fetcher, if multiple fetcher are usedoelint.vars.srcurigittag - 'tag' in SRC_URI-options leads to not-reproducible buildsoelint.vars.srcurioptions - Unsupported fetcher or invalid options detectedoelint.vars.srcurisrcrevtag - 'tag' in SRC_URI and a SRCREV for the same component doesn't computeoelint.vars.summary80chars - SUMMARY should max. be 80 characters longoelint.vars.summarylinebreaks - No line breaks in SUMMARYoelint.vars.valuequoted - Variable values should be properly quotedoelint.vars.virtual - no virtual/ items in RDEPENDS/RPROVIDESNon-default rulesetsTo enable rulesets that are not part of the standard ruleset pass--addrules <ruleset-name>to CLI.These rules are sometimes contrary to OE-style-guide, so use them with caution.jetm rulesetTo enable pass--addrules jetmto CLI.Rules marked with[F]are able to perform automatic fixing.oelint.jetm.vars.dependssingleline - Each [R]DEPENDS entry should be put into a single lineWriting your own additional rulesBy passing--customrulesvia CLI you could add additional rules to be checked.
The argument should point to a directory - every class derived fromRulewill be automatically loaded.
Please use the following as a template for your own:fromoelint_adv.cls_ruleimportRuleclassFooMagicRule(Rule):def__init__(self):super().__init__(id="foocorp.foo.magic",severity="error",message="Too much foo happening here")defcheck(self,_file,stash):res=[]items=stash.GetItemsFor(filename=_file)foriinitems:if"Foo"ini.Raw:res+=self.finding(i.Origin,i.InFileLine)returnres# To provide automatic fixing capability# add the following optional functiondeffix(self,_file,stash):res=[]items=stash.GetItemsFor(filename=_file)foriinitems:if'Foo'ini.Raw:# you have to replace the content of `RealRaw` and `Raw`# with the fixed content# `Raw` is the raw block with expanded inlines blocks# `RealRaw` is the raw block without any modifications#           this is what will be actually written to the filei.RealRaw=i.RealRaw.replace('Foo','Bar')i.Raw=i.Raw.replace('Foo','Bar')# Return the file name to signalize that fixes have been# appliedres.append(_file)returnresFor more details please see the function docstrings of the API.You can find this example also in the developmentsource treeAdditional real-life examples can be found in e.g.meta-rubygemsRelease constrained rulesRules can be also configured to work on specific releases of YP only, if determined not to be applicable, the rules will
be skipped during the loading process and therefore won't show up if e.g.--print-rulefileis usedRules working up to a certain releasefromoelint_adv.cls_ruleimportRuleclassFooMagicRule(Rule):def__init__(self):super().__init__(id="foocorp.foo.magic",severity="error",message="Too much foo happening here",valid_till_release="kirkstone")Would enable the rule, but only if--releaseis set to a YP release earlier thankirkstoneRules working from a certain releasefromoelint_adv.cls_ruleimportRuleclassFooMagicRule(Rule):def__init__(self):super().__init__(id="foocorp.foo.magic",severity="error",message="Too much foo happening here",valid_from_release="kirkstone")Would enable the rule, but only if--releaseis set to a YP release later thankirkstone(includingkirkstone)Enable special settings per releasefromoelint_adv.cls_ruleimportRuleclassFooMagicRule(Rule):def__init__(self):super().__init__(id="foocorp.foo.magic",severity="error",message="Too much foo happening here")defcheck_release_range(self,release_range:List[str])->bool:if'kirkstone'inrelease_range:self._we_are_running_on_kirkstone=Trueself.Appendix.append('kirkstone')returnsuper().check_release_range(release_range)Enables the specialAppendixkirkstone, ifkirkstoneis part of the calculated--releaselist.It also sets the variableself._we_are_running_on_kirkstone, which can be used as part ofcheck()to
code special code paths.Defining a rulesetIf you pass the option--rulefileyou could define the rules to be checked and their severity via a simple json file.The rule file could look like this:{"<rule>":"<severity>"}to override the severity, or{"<rule>":""}to keep the original severity.Example{"oelint.file.includenotfound":"","oelint.file.requirenotfound":"warning"}would enable the two rulesoelint.file.includenotfoundandoelint.file.requirenotfound.
The severity ofoelint.file.includenotfoundwill be the default of the tool, whileoelint.file.requirenotfoundwill reportwarninginstead of the original suggested severity.Adding additional constantsPlease seeoelint-parserfor further details, how to add your own constants to the parser.Output message formatYou can freely define a custom output format.
The following placeholder symbols will be automatically replacednamereplaced by{path}path of the file{line}line of the finding{severity}severity of the finding{id}error-ID of the finding{msg}description of the findingConfiguration fileYou can define your own global or project wide defaults for all CLI parameters with an ini-style configuration file.In the following order files are probedfile pointed to by environment variableOELINT_CONFIGfile.oelint.cfgin current work directoryfile.oelint.cfgin yourHOMEdirectoryExplicitly passed options to CLI are always chosen over the defaults defined by the configuration fileFile format[oelint]# this will set the --nowarn parameter automaticallynowarn=True# this will set A + B as suppress item# use indent (tab) and line breaks for multiple itemssuppress=AB# this will set messageformat parametermessageformat={severity}:{id}:{msg}# will configure --release to dunfellrelease=dunfellYou can find an example filehereInline suppressionYou can suppress one or more checks on a line by line basis# nooelint: <id>[,<id>,...]suppresses all the specified IDs for the next line.
Multiple IDs can be separated by commas.Example# nooelint: oelint.vars.insaneskip
INSANE_SKIP:${PN} = "foo"will not warn about the usage ofINSANE_SKIP.Configure your custom machine or distro settingsYou can letoelint-advknow about your customMACHINEandDISTROoverrides, so they won't produce any findings, when
used in your setup.Create a layer specific oelint configuration fileCopy over the template thisfileto the root of your layerLAYER_PATH=<pathtoyourlayer>
cpdocs/.oelint.cfg.custom-layer$LAYER_PATH/.oelint.cfgCreate the known MACHINE and DISTRO settingsSource your bitbake build directory and run the following commands (**) (***)LAYER_PATH=<pathtoyourlayer>
bitbake-getvar--quiet--valueMACHINEOVERRIDES|tr':''\n'|jq-Rn'{replacements:{ machines: [inputs]}}'>$LAYER_PATH/.oelint-custom-machines.json
bitbake-getvar--quiet--valueDISTROOVERRIDES|tr':''\n'|jq-Rn'{replacements:{ distros: [inputs]}}'>$LAYER_PATH/.oelint-custom-distros.json(**) you'll need to havejqinstalled on your local machine.(***)bitbake-getvarcommand is available sincekirkstonerelease. For older release you can usebitbake core-image-minimal -e | grep ^MACHINEOVERRIDESresp.bitbake core-image-minimal -e | grep ^DISTROOVERRIDESand pass them into the rest of the pipe.vscode extensionFind the extension in themarketplace, or search foroelint-vscode.Vim / NeoVim integrationIntegration for Vim / NeoVim is provided byaleornvim-lint.Jenkins integrationJenkins integration is provided bywarnings-ng.Missing anything?You think there's something missing, wrong, 'improvable'...
Just file an issue to get in contact.ContributeAny sort of ideas, pull requests, bug reports, reports of false positives are welcome.
This project is open to anyone - no pitfalls or legal inconveniences.