mirror of
https://git.yoctoproject.org/poky
synced 2026-09-12 15:49:36 +02:00
Compare commits
3 Commits
scarthgap-
...
yocto-2.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e392026ff | ||
|
|
41136dd0cf | ||
|
|
80baa2d1fb |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -8,7 +8,6 @@ pstage/
|
|||||||
scripts/oe-git-proxy-socks
|
scripts/oe-git-proxy-socks
|
||||||
sources/
|
sources/
|
||||||
meta-*/
|
meta-*/
|
||||||
buildtools/
|
|
||||||
!meta-skeleton
|
!meta-skeleton
|
||||||
!meta-selftest
|
!meta-selftest
|
||||||
hob-image-*.bb
|
hob-image-*.bb
|
||||||
@@ -31,9 +30,3 @@ pull-*/
|
|||||||
bitbake/lib/toaster/contrib/tts/backlog.txt
|
bitbake/lib/toaster/contrib/tts/backlog.txt
|
||||||
bitbake/lib/toaster/contrib/tts/log/*
|
bitbake/lib/toaster/contrib/tts/log/*
|
||||||
bitbake/lib/toaster/contrib/tts/.cache/*
|
bitbake/lib/toaster/contrib/tts/.cache/*
|
||||||
bitbake/lib/bb/tests/runqueue-tests/bitbake-cookerdaemon.log
|
|
||||||
_toaster_clones/
|
|
||||||
downloads/
|
|
||||||
sstate-cache/
|
|
||||||
toaster.sqlite
|
|
||||||
.vscode/
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
# Template settings
|
# Template settings
|
||||||
TEMPLATECONF=${TEMPLATECONF:-meta-poky/conf/templates/default}
|
TEMPLATECONF=${TEMPLATECONF:-meta-poky/conf}
|
||||||
|
|||||||
24
LICENSE
24
LICENSE
@@ -1,20 +1,14 @@
|
|||||||
Different components of OpenEmbedded are under different licenses (a mix
|
Different components of OpenEmbedded are under different licenses (a mix
|
||||||
of MIT and GPLv2). See LICENSE.GPL-2.0-only and LICENSE.MIT for further
|
of MIT and GPLv2). Please see:
|
||||||
details of the individual licenses.
|
|
||||||
|
meta/COPYING.GPLv2 (GPLv2)
|
||||||
|
meta/COPYING.MIT (MIT)
|
||||||
|
meta-selftest/COPYING.MIT (MIT)
|
||||||
|
meta-skeleton/COPYING.MIT (MIT)
|
||||||
|
|
||||||
All metadata is MIT licensed unless otherwise stated. Source code
|
All metadata is MIT licensed unless otherwise stated. Source code
|
||||||
included in tree for individual recipes (e.g. patches) are under
|
included in tree for individual recipes is under the LICENSE stated in
|
||||||
the LICENSE stated in the associated recipe (.bb file) unless
|
the associated recipe (.bb file) unless otherwise stated.
|
||||||
otherwise stated.
|
|
||||||
|
|
||||||
License information for any other files is either explicitly stated
|
License information for any other files is either explicitly stated
|
||||||
or defaults to GPL version 2 only.
|
or defaults to GPL version 2.
|
||||||
|
|
||||||
Individual files contain the following style tags instead of the full license
|
|
||||||
text to identify their license:
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
This enables machine processing of license information based on the SPDX
|
|
||||||
License Identifiers that are here available: http://spdx.org/licenses/
|
|
||||||
|
|||||||
@@ -1,288 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
Note:
|
|
||||||
Individual files contain the following tag instead of the full license text.
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
This enables machine processing of license information based on the SPDX
|
|
||||||
License Identifiers that are here available: http://spdx.org/licenses/
|
|
||||||
25
LICENSE.MIT
25
LICENSE.MIT
@@ -1,25 +0,0 @@
|
|||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
Individual files contain the following tag instead of the full license text.
|
|
||||||
|
|
||||||
SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
This enables machine processing of license information based on the SPDX
|
|
||||||
License Identifiers that are here available: http://spdx.org/licenses/
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
OpenEmbedded-Core and Yocto Project Maintainer Information
|
|
||||||
==========================================================
|
|
||||||
|
|
||||||
OpenEmbedded and Yocto Project work jointly together to maintain the metadata,
|
|
||||||
layers, tools and sub-projects that make up their ecosystems.
|
|
||||||
|
|
||||||
The projects operate through collaborative development. This currently takes
|
|
||||||
place on mailing lists for many components as the "pull request on github"
|
|
||||||
workflow works well for single or small numbers of maintainers but we have
|
|
||||||
a large number, all with different specialisms and benefit from the mailing
|
|
||||||
list review process. Changes therefore undergo peer review through mailing
|
|
||||||
lists in many cases.
|
|
||||||
|
|
||||||
This file aims to acknowledge people with specific skills/knowledge/interest
|
|
||||||
both to recognise their contributions but also empower them to help lead and
|
|
||||||
curate those components. Where we have people with specialist knowledge in
|
|
||||||
particular areas, during review patches/feedback from these people in these
|
|
||||||
areas would generally carry weight.
|
|
||||||
|
|
||||||
This file is maintained in OE-Core but may refer to components that are separate
|
|
||||||
to it if that makes sense in the context of maintainership. The README of specific
|
|
||||||
layers and components should ultimately be definitive about the patch process and
|
|
||||||
maintainership for the component.
|
|
||||||
|
|
||||||
Recipe Maintainers
|
|
||||||
------------------
|
|
||||||
|
|
||||||
See meta/conf/distro/include/maintainers.inc
|
|
||||||
|
|
||||||
Component/Subsystem Maintainers
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
* Kernel (inc. linux-yocto, perf): Bruce Ashfield
|
|
||||||
* Reproducible Builds: Joshua Watt
|
|
||||||
* Toaster: David Reyna
|
|
||||||
* Hash-Equivalence: Joshua Watt
|
|
||||||
* Recipe upgrade infrastructure: Alex Kanavin
|
|
||||||
* Toolchain: Khem Raj
|
|
||||||
* ptest-runner: Aníbal Limón
|
|
||||||
* opkg: Alex Stewart
|
|
||||||
* devtool: Saul Wold
|
|
||||||
* eSDK: Saul Wold
|
|
||||||
* overlayfs: Vyacheslav Yurkov
|
|
||||||
|
|
||||||
Maintainers needed
|
|
||||||
------------------
|
|
||||||
|
|
||||||
* Pseudo
|
|
||||||
* Layer Index
|
|
||||||
* recipetool
|
|
||||||
* QA framework/automated testing
|
|
||||||
* error reporting system/web UI
|
|
||||||
* wic
|
|
||||||
* Patchwork
|
|
||||||
* Patchtest
|
|
||||||
* Matchbox
|
|
||||||
* Sato
|
|
||||||
* Autobuilder
|
|
||||||
|
|
||||||
Layer Maintainers needed
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
* meta-gplv2 (ideally new strategy but active maintainer welcome)
|
|
||||||
|
|
||||||
Shadow maintainers/development needed
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
* toaster
|
|
||||||
* bitbake
|
|
||||||
|
|
||||||
|
|
||||||
5
MEMORIAM
5
MEMORIAM
@@ -1,5 +0,0 @@
|
|||||||
Some project contributors who are sadly no longer with us:
|
|
||||||
|
|
||||||
Greg Gilbert (treke) - Ahead of his time with licensing
|
|
||||||
Thomas Wood (thos) - Creator of the original sato
|
|
||||||
Scott Rifenbark (scottrif) - Our long standing techwriter whose words live on
|
|
||||||
26
README.LSB
Normal file
26
README.LSB
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
OE-Core aims to be able to provide basic LSB compatible images. There
|
||||||
|
are some challenges for OE as LSB isn't always 100% relevant to its
|
||||||
|
target embedded and IoT audiences.
|
||||||
|
|
||||||
|
One challenge is that the LSB spec is no longer being actively
|
||||||
|
developed [https://github.com/LinuxStandardBase/lsb] and has
|
||||||
|
components which are end of life or significantly dated. OE
|
||||||
|
therefore provides compatibility with the following caveats:
|
||||||
|
|
||||||
|
* Qt4 is provided by the separate meta-qt4 layer. Its noted that Qt4
|
||||||
|
is end of life and this isn't something the core project regularly
|
||||||
|
tests any longer. Users are recommended to group together to support
|
||||||
|
maintenance of that layer. [http://git.yoctoproject.org/cgit/cgit.cgi/meta-qt4/]
|
||||||
|
|
||||||
|
* mailx has been dropped since its no longer being developed upstream
|
||||||
|
and there are better, more modern replacements such as s-nail
|
||||||
|
(http://sdaoden.eu/code.html) or mailutils (http://mailutils.org/).
|
||||||
|
|
||||||
|
* A few perl modules that were required by LSB 4.x aren't provided:
|
||||||
|
libclass-isa, libenv, libdumpvalue, libfile-checktree,
|
||||||
|
libi18n-collate, libpod-plainer.
|
||||||
|
|
||||||
|
* libpng 1.2 isn't provided; oe-core includes the latest release of libpng
|
||||||
|
instead.
|
||||||
|
|
||||||
|
* pax (POSIX standard archive) tool is not provided.
|
||||||
29
README.OE-Core
Normal file
29
README.OE-Core
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
OpenEmbedded-Core
|
||||||
|
=================
|
||||||
|
|
||||||
|
OpenEmbedded-Core is a layer containing the core metadata for current versions
|
||||||
|
of OpenEmbedded. It is distro-less (can build a functional image with
|
||||||
|
DISTRO = "nodistro") and contains only emulated machine support.
|
||||||
|
|
||||||
|
For information about OpenEmbedded, see the OpenEmbedded website:
|
||||||
|
http://www.openembedded.org/
|
||||||
|
|
||||||
|
The Yocto Project has extensive documentation about OE including a reference manual
|
||||||
|
which can be found at:
|
||||||
|
http://yoctoproject.org/documentation
|
||||||
|
|
||||||
|
|
||||||
|
Contributing
|
||||||
|
------------
|
||||||
|
|
||||||
|
Please refer to
|
||||||
|
http://www.openembedded.org/wiki/How_to_submit_a_patch_to_OpenEmbedded
|
||||||
|
for guidelines on how to submit patches.
|
||||||
|
|
||||||
|
Mailing list:
|
||||||
|
|
||||||
|
http://lists.openembedded.org/mailman/listinfo/openembedded-core
|
||||||
|
|
||||||
|
Source code:
|
||||||
|
|
||||||
|
http://git.openembedded.org/openembedded-core/
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
OpenEmbedded-Core
|
|
||||||
=================
|
|
||||||
|
|
||||||
OpenEmbedded-Core is a layer containing the core metadata for current versions
|
|
||||||
of OpenEmbedded. It is distro-less (can build a functional image with
|
|
||||||
DISTRO = "nodistro") and contains only emulated machine support.
|
|
||||||
|
|
||||||
For information about OpenEmbedded, see the OpenEmbedded website:
|
|
||||||
https://www.openembedded.org/
|
|
||||||
|
|
||||||
The Yocto Project has extensive documentation about OE including a reference manual
|
|
||||||
which can be found at:
|
|
||||||
https://docs.yoctoproject.org/
|
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
------------
|
|
||||||
|
|
||||||
Please refer to our contributor guide here: https://docs.yoctoproject.org/dev/contributor-guide/
|
|
||||||
for full details on how to submit changes.
|
|
||||||
|
|
||||||
As a quick guide, patches should be sent to openembedded-core@lists.openembedded.org
|
|
||||||
The git command to do that would be:
|
|
||||||
|
|
||||||
git send-email -M -1 --to openembedded-core@lists.openembedded.org
|
|
||||||
|
|
||||||
Mailing list:
|
|
||||||
|
|
||||||
https://lists.openembedded.org/g/openembedded-core
|
|
||||||
|
|
||||||
Source code:
|
|
||||||
|
|
||||||
https://git.openembedded.org/openembedded-core/
|
|
||||||
1
README.hardware
Symbolic link
1
README.hardware
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
meta-yocto-bsp/README.hardware
|
||||||
@@ -1 +0,0 @@
|
|||||||
meta-yocto-bsp/README.hardware.md
|
|
||||||
1
README.poky
Symbolic link
1
README.poky
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
meta-poky/README.poky
|
||||||
@@ -1 +0,0 @@
|
|||||||
meta-poky/README.poky.md
|
|
||||||
22
SECURITY.md
22
SECURITY.md
@@ -1,22 +0,0 @@
|
|||||||
How to Report a Potential Vulnerability?
|
|
||||||
========================================
|
|
||||||
|
|
||||||
If you would like to report a public issue (for example, one with a released
|
|
||||||
CVE number), please report it using the
|
|
||||||
[https://bugzilla.yoctoproject.org/enter_bug.cgi?product=Security Security Bugzilla]
|
|
||||||
|
|
||||||
If you are dealing with a not-yet released or urgent issue, please send a
|
|
||||||
message to security AT yoctoproject DOT org, including as many details as
|
|
||||||
possible: the layer or software module affected, the recipe and its version,
|
|
||||||
and any example code, if available.
|
|
||||||
|
|
||||||
Branches maintained with security fixes
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
See [https://wiki.yoctoproject.org/wiki/Stable_Release_and_LTS Stable release and LTS]
|
|
||||||
for detailed info regarding the policies and maintenance of Stable branches.
|
|
||||||
|
|
||||||
The [https://wiki.yoctoproject.org/wiki/Releases Release page] contains a list of all
|
|
||||||
releases of the Yocto Project. Versions in grey are no longer actively maintained with
|
|
||||||
security patches, but well-tested patches may still be accepted for them for
|
|
||||||
significant issues.
|
|
||||||
339
bitbake/COPYING
Normal file
339
bitbake/COPYING
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
19
bitbake/HEADER
Normal file
19
bitbake/HEADER
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# ex:ts=4:sw=4:sts=4:et
|
||||||
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||||
|
#
|
||||||
|
# <one line to give the program's name and a brief idea of what it does.>
|
||||||
|
# Copyright (C) <year> <name of author>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
@@ -1,13 +1,4 @@
|
|||||||
BitBake is licensed under the GNU General Public License version 2.0. See
|
BitBake is licensed under the GNU General Public License version 2.0. See COPYING for further details.
|
||||||
LICENSE.GPL-2.0-only for further details.
|
|
||||||
|
|
||||||
Individual files contain the following style tags instead of the full license text:
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
This enables machine processing of license information based on the SPDX
|
|
||||||
License Identifiers that are here available: http://spdx.org/licenses/
|
|
||||||
|
|
||||||
|
|
||||||
The following external components are distributed with this software:
|
The following external components are distributed with this software:
|
||||||
|
|
||||||
@@ -26,4 +17,3 @@ Foundation and individual contributors.
|
|||||||
* Font Awesome fonts redistributed under the SIL Open Font License 1.1
|
* Font Awesome fonts redistributed under the SIL Open Font License 1.1
|
||||||
|
|
||||||
* simplediff is distributed under the zlib license.
|
* simplediff is distributed under the zlib license.
|
||||||
|
|
||||||
|
|||||||
@@ -1,288 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
Note:
|
|
||||||
Individual files contain the following tag instead of the full license text.
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
This enables machine processing of license information based on the SPDX
|
|
||||||
License Identifiers that are here available: http://spdx.org/licenses/
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
Individual files contain the following tag instead of the full license text.
|
|
||||||
|
|
||||||
SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
This enables machine processing of license information based on the SPDX
|
|
||||||
License Identifiers that are here available: http://spdx.org/licenses/
|
|
||||||
@@ -7,57 +7,29 @@ One of BitBake's main users, OpenEmbedded, takes this core and builds embedded L
|
|||||||
stacks using a task-oriented approach.
|
stacks using a task-oriented approach.
|
||||||
|
|
||||||
For information about Bitbake, see the OpenEmbedded website:
|
For information about Bitbake, see the OpenEmbedded website:
|
||||||
https://www.openembedded.org/
|
http://www.openembedded.org/
|
||||||
|
|
||||||
Bitbake plain documentation can be found under the doc directory or its integrated
|
Bitbake plain documentation can be found under the doc directory or its integrated
|
||||||
html version at the Yocto Project website:
|
html version at the Yocto Project website:
|
||||||
https://docs.yoctoproject.org
|
http://yoctoproject.org/documentation
|
||||||
|
|
||||||
Bitbake requires Python version 3.8 or newer.
|
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Please refer to our contributor guide here: https://docs.yoctoproject.org/contributor-guide/
|
Please refer to
|
||||||
for full details on how to submit changes.
|
http://www.openembedded.org/wiki/How_to_submit_a_patch_to_OpenEmbedded
|
||||||
|
for guidelines on how to submit patches, just note that the latter documentation is intended
|
||||||
As a quick guide, patches should be sent to bitbake-devel@lists.openembedded.org
|
for OpenEmbedded (and its core) not bitbake patches (bitbake-devel@lists.openembedded.org)
|
||||||
The git command to do that would be:
|
but in general main guidelines apply. Once the commit(s) have been created, the way to send
|
||||||
|
the patch is through git-send-email. For example, to send the last commit (HEAD) on current
|
||||||
|
branch, type:
|
||||||
|
|
||||||
git send-email -M -1 --to bitbake-devel@lists.openembedded.org
|
git send-email -M -1 --to bitbake-devel@lists.openembedded.org
|
||||||
|
|
||||||
If you're sending a patch related to the BitBake manual, make sure you copy
|
|
||||||
the Yocto Project documentation mailing list:
|
|
||||||
|
|
||||||
git send-email -M -1 --to bitbake-devel@lists.openembedded.org --cc docs@lists.yoctoproject.org
|
|
||||||
|
|
||||||
Mailing list:
|
Mailing list:
|
||||||
|
|
||||||
https://lists.openembedded.org/g/bitbake-devel
|
http://lists.openembedded.org/mailman/listinfo/bitbake-devel
|
||||||
|
|
||||||
Source code:
|
Source code:
|
||||||
|
|
||||||
https://git.openembedded.org/bitbake/
|
http://git.openembedded.org/bitbake/
|
||||||
|
|
||||||
Testing
|
|
||||||
-------
|
|
||||||
|
|
||||||
Bitbake has a testsuite located in lib/bb/tests/ whichs aim to try and prevent regressions.
|
|
||||||
You can run this with "bitbake-selftest". In particular the fetcher is well covered since
|
|
||||||
it has so many corner cases. The datastore has many tests too. Testing with the testsuite is
|
|
||||||
recommended before submitting patches, particularly to the fetcher and datastore. We also
|
|
||||||
appreciate new test cases and may require them for more obscure issues.
|
|
||||||
|
|
||||||
To run the tests "zstd" and "git" must be installed.
|
|
||||||
|
|
||||||
The assumption is made that this testsuite is run from an initialized OpenEmbedded build
|
|
||||||
environment (i.e. `source oe-init-build-env` is used). If this is not the case, run the
|
|
||||||
testsuite as follows:
|
|
||||||
|
|
||||||
export PATH=$(pwd)/bin:$PATH
|
|
||||||
bin/bitbake-selftest
|
|
||||||
|
|
||||||
The testsuite can alternatively be executed using pytest, e.g. obtained from PyPI (in this
|
|
||||||
case, the PATH is configured automatically):
|
|
||||||
|
|
||||||
pytest
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
How to Report a Potential Vulnerability?
|
|
||||||
========================================
|
|
||||||
|
|
||||||
If you would like to report a public issue (for example, one with a released
|
|
||||||
CVE number), please report it using the
|
|
||||||
[https://bugzilla.yoctoproject.org/enter_bug.cgi?product=Security Security Bugzilla].
|
|
||||||
If you have a patch ready, submit it following the same procedure as any other
|
|
||||||
patch as described in README.md.
|
|
||||||
|
|
||||||
If you are dealing with a not-yet released or urgent issue, please send a
|
|
||||||
message to security AT yoctoproject DOT org, including as many details as
|
|
||||||
possible: the layer or software module affected, the recipe and its version,
|
|
||||||
and any example code, if available.
|
|
||||||
|
|
||||||
Branches maintained with security fixes
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
See [https://wiki.yoctoproject.org/wiki/Stable_Release_and_LTS Stable release and LTS]
|
|
||||||
for detailed info regarding the policies and maintenance of Stable branches.
|
|
||||||
|
|
||||||
The [https://wiki.yoctoproject.org/wiki/Releases Release page] contains a list of all
|
|
||||||
releases of the Yocto Project. Versions in grey are no longer actively maintained with
|
|
||||||
security patches, but well-tested patches may still be accepted for them for
|
|
||||||
significant issues.
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# ex:ts=4:sw=4:sts=4:et
|
||||||
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
# Copyright (C) 2003, 2004 Chris Larson
|
||||||
# Copyright (C) 2003, 2004 Phil Blundell
|
# Copyright (C) 2003, 2004 Phil Blundell
|
||||||
@@ -7,13 +9,21 @@
|
|||||||
# Copyright (C) 2005 ROAD GmbH
|
# Copyright (C) 2005 ROAD GmbH
|
||||||
# Copyright (C) 2006 Richard Purdie
|
# Copyright (C) 2006 Richard Purdie
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
#
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
|
||||||
warnings.simplefilter("default")
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)),
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)),
|
||||||
'lib'))
|
'lib'))
|
||||||
@@ -25,9 +35,10 @@ except RuntimeError as exc:
|
|||||||
from bb import cookerdata
|
from bb import cookerdata
|
||||||
from bb.main import bitbake_main, BitBakeConfigParameters, BBMainException
|
from bb.main import bitbake_main, BitBakeConfigParameters, BBMainException
|
||||||
|
|
||||||
bb.utils.check_system_locale()
|
if sys.getfilesystemencoding() != "utf-8":
|
||||||
|
sys.exit("Please use a locale setting which supports UTF-8 (such as LANG=en_US.UTF-8).\nPython can't change the filesystem locale after loading so we need a UTF-8 when Python starts or things won't work.")
|
||||||
|
|
||||||
__version__ = "2.8.1"
|
__version__ = "1.42.0"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if __version__ != bb.__version__:
|
if __version__ != bb.__version__:
|
||||||
|
|||||||
@@ -5,14 +5,22 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2012-2013, 2017 Intel Corporation
|
# Copyright (C) 2012-2013, 2017 Intel Corporation
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
#
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.simplefilter("default")
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import pickle
|
import pickle
|
||||||
@@ -28,7 +36,6 @@ logger = bb.msg.logger_create(myname)
|
|||||||
|
|
||||||
is_dump = myname == 'bitbake-dumpsig'
|
is_dump = myname == 'bitbake-dumpsig'
|
||||||
|
|
||||||
|
|
||||||
def find_siginfo(tinfoil, pn, taskname, sigs=None):
|
def find_siginfo(tinfoil, pn, taskname, sigs=None):
|
||||||
result = None
|
result = None
|
||||||
tinfoil.set_event_mask(['bb.event.FindSigInfoResult',
|
tinfoil.set_event_mask(['bb.event.FindSigInfoResult',
|
||||||
@@ -54,7 +61,6 @@ def find_siginfo(tinfoil, pn, taskname, sigs=None):
|
|||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def find_siginfo_task(bbhandler, pn, taskname, sig1=None, sig2=None):
|
def find_siginfo_task(bbhandler, pn, taskname, sig1=None, sig2=None):
|
||||||
""" Find the most recent signature files for the specified PN/task """
|
""" Find the most recent signature files for the specified PN/task """
|
||||||
|
|
||||||
@@ -63,26 +69,22 @@ def find_siginfo_task(bbhandler, pn, taskname, sig1=None, sig2=None):
|
|||||||
|
|
||||||
if sig1 and sig2:
|
if sig1 and sig2:
|
||||||
sigfiles = find_siginfo(bbhandler, pn, taskname, [sig1, sig2])
|
sigfiles = find_siginfo(bbhandler, pn, taskname, [sig1, sig2])
|
||||||
if not sigfiles:
|
if len(sigfiles) == 0:
|
||||||
logger.error('No sigdata files found matching %s %s matching either %s or %s' % (pn, taskname, sig1, sig2))
|
logger.error('No sigdata files found matching %s %s matching either %s or %s' % (pn, taskname, sig1, sig2))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
elif sig1 not in sigfiles:
|
elif not sig1 in sigfiles:
|
||||||
logger.error('No sigdata files found matching %s %s with signature %s' % (pn, taskname, sig1))
|
logger.error('No sigdata files found matching %s %s with signature %s' % (pn, taskname, sig1))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
elif sig2 not in sigfiles:
|
elif not sig2 in sigfiles:
|
||||||
logger.error('No sigdata files found matching %s %s with signature %s' % (pn, taskname, sig2))
|
logger.error('No sigdata files found matching %s %s with signature %s' % (pn, taskname, sig2))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
latestfiles = [sigfiles[sig1], sigfiles[sig2]]
|
||||||
latestfiles = [sigfiles[sig1]['path'], sigfiles[sig2]['path']]
|
|
||||||
else:
|
else:
|
||||||
sigfiles = find_siginfo(bbhandler, pn, taskname)
|
filedates = find_siginfo(bbhandler, pn, taskname)
|
||||||
latestsigs = sorted(sigfiles.keys(), key=lambda h: sigfiles[h]['time'])[-2:]
|
latestfiles = sorted(filedates.keys(), key=lambda f: filedates[f])[-2:]
|
||||||
if not latestsigs:
|
if not latestfiles:
|
||||||
logger.error('No sigdata files found matching %s %s' % (pn, taskname))
|
logger.error('No sigdata files found matching %s %s' % (pn, taskname))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
latestfiles = [sigfiles[latestsigs[0]]['path']]
|
|
||||||
if len(latestsigs) > 1:
|
|
||||||
latestfiles.append(sigfiles[latestsigs[1]]['path'])
|
|
||||||
|
|
||||||
return latestfiles
|
return latestfiles
|
||||||
|
|
||||||
@@ -93,17 +95,17 @@ def recursecb(key, hash1, hash2):
|
|||||||
hashfiles = find_siginfo(tinfoil, key, None, hashes)
|
hashfiles = find_siginfo(tinfoil, key, None, hashes)
|
||||||
|
|
||||||
recout = []
|
recout = []
|
||||||
if not hashfiles:
|
if len(hashfiles) == 0:
|
||||||
recout.append("Unable to find matching sigdata for %s with hashes %s or %s" % (key, hash1, hash2))
|
recout.append("Unable to find matching sigdata for %s with hashes %s or %s" % (key, hash1, hash2))
|
||||||
elif hash1 not in hashfiles:
|
elif not hash1 in hashfiles:
|
||||||
recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash1))
|
recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash1))
|
||||||
elif hash2 not in hashfiles:
|
elif not hash2 in hashfiles:
|
||||||
recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash2))
|
recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash2))
|
||||||
else:
|
else:
|
||||||
out2 = bb.siggen.compare_sigfiles(hashfiles[hash1]['path'], hashfiles[hash2]['path'], recursecb, color=color)
|
out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb, color=color)
|
||||||
for change in out2:
|
for change in out2:
|
||||||
for line in change.splitlines():
|
for line in change.splitlines():
|
||||||
recout.append(' ' + line)
|
recout.append(' ' + line)
|
||||||
|
|
||||||
return recout
|
return recout
|
||||||
|
|
||||||
@@ -117,36 +119,36 @@ parser.add_argument('-D', '--debug',
|
|||||||
|
|
||||||
if is_dump:
|
if is_dump:
|
||||||
parser.add_argument("-t", "--task",
|
parser.add_argument("-t", "--task",
|
||||||
help="find the signature data file for the last run of the specified task",
|
help="find the signature data file for the last run of the specified task",
|
||||||
action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
|
action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
|
||||||
|
|
||||||
parser.add_argument("sigdatafile1",
|
parser.add_argument("sigdatafile1",
|
||||||
help="Signature file to dump. Not used when using -t/--task.",
|
help="Signature file to dump. Not used when using -t/--task.",
|
||||||
action="store", nargs='?', metavar="sigdatafile")
|
action="store", nargs='?', metavar="sigdatafile")
|
||||||
else:
|
else:
|
||||||
parser.add_argument('-c', '--color',
|
parser.add_argument('-c', '--color',
|
||||||
help='Colorize the output (where %(metavar)s is %(choices)s)',
|
help='Colorize the output (where %(metavar)s is %(choices)s)',
|
||||||
choices=['auto', 'always', 'never'], default='auto', metavar='color')
|
choices=['auto', 'always', 'never'], default='auto', metavar='color')
|
||||||
|
|
||||||
parser.add_argument('-d', '--dump',
|
parser.add_argument('-d', '--dump',
|
||||||
help='Dump the last signature data instead of comparing (equivalent to using bitbake-dumpsig)',
|
help='Dump the last signature data instead of comparing (equivalent to using bitbake-dumpsig)',
|
||||||
action='store_true')
|
action='store_true')
|
||||||
|
|
||||||
parser.add_argument("-t", "--task",
|
parser.add_argument("-t", "--task",
|
||||||
help="find the signature data files for the last two runs of the specified task and compare them",
|
help="find the signature data files for the last two runs of the specified task and compare them",
|
||||||
action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
|
action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
|
||||||
|
|
||||||
parser.add_argument("-s", "--signature",
|
parser.add_argument("-s", "--signature",
|
||||||
help="With -t/--task, specify the signatures to look for instead of taking the last two",
|
help="With -t/--task, specify the signatures to look for instead of taking the last two",
|
||||||
action="store", dest="sigargs", nargs=2, metavar=('fromsig', 'tosig'))
|
action="store", dest="sigargs", nargs=2, metavar=('fromsig', 'tosig'))
|
||||||
|
|
||||||
parser.add_argument("sigdatafile1",
|
parser.add_argument("sigdatafile1",
|
||||||
help="First signature file to compare (or signature file to dump, if second not specified). Not used when using -t/--task.",
|
help="First signature file to compare (or signature file to dump, if second not specified). Not used when using -t/--task.",
|
||||||
action="store", nargs='?')
|
action="store", nargs='?')
|
||||||
|
|
||||||
parser.add_argument("sigdatafile2",
|
parser.add_argument("sigdatafile2",
|
||||||
help="Second signature file to compare",
|
help="Second signature file to compare",
|
||||||
action="store", nargs='?')
|
action="store", nargs='?')
|
||||||
|
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
if is_dump:
|
if is_dump:
|
||||||
@@ -164,8 +166,7 @@ if options.taskargs:
|
|||||||
with bb.tinfoil.Tinfoil() as tinfoil:
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
||||||
tinfoil.prepare(config_only=True)
|
tinfoil.prepare(config_only=True)
|
||||||
if not options.dump and options.sigargs:
|
if not options.dump and options.sigargs:
|
||||||
files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1], options.sigargs[0],
|
files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1], options.sigargs[0], options.sigargs[1])
|
||||||
options.sigargs[1])
|
|
||||||
else:
|
else:
|
||||||
files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1])
|
files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1])
|
||||||
|
|
||||||
@@ -174,8 +175,7 @@ if options.taskargs:
|
|||||||
output = bb.siggen.dump_sigfile(files[-1])
|
output = bb.siggen.dump_sigfile(files[-1])
|
||||||
else:
|
else:
|
||||||
if len(files) < 2:
|
if len(files) < 2:
|
||||||
logger.error('Only one matching sigdata file found for the specified task (%s %s)' % (
|
logger.error('Only one matching sigdata file found for the specified task (%s %s)' % (options.taskargs[0], options.taskargs[1]))
|
||||||
options.taskargs[0], options.taskargs[1]))
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Recurse into signature comparison
|
# Recurse into signature comparison
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
#! /usr/bin/env python3
|
|
||||||
#
|
|
||||||
# Copyright (C) 2021 Richard Purdie
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import warnings
|
|
||||||
warnings.simplefilter("default")
|
|
||||||
|
|
||||||
bindir = os.path.dirname(__file__)
|
|
||||||
topdir = os.path.dirname(bindir)
|
|
||||||
sys.path[0:0] = [os.path.join(topdir, 'lib')]
|
|
||||||
|
|
||||||
import bb.tinfoil
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(description="Bitbake Query Variable")
|
|
||||||
parser.add_argument("variable", help="variable name to query")
|
|
||||||
parser.add_argument("-r", "--recipe", help="Recipe name to query", default=None, required=False)
|
|
||||||
parser.add_argument('-u', '--unexpand', help='Do not expand the value (with --value)', action="store_true")
|
|
||||||
parser.add_argument('-f', '--flag', help='Specify a variable flag to query (with --value)', default=None)
|
|
||||||
parser.add_argument('--value', help='Only report the value, no history and no variable name', action="store_true")
|
|
||||||
parser.add_argument('-q', '--quiet', help='Silence bitbake server logging', action="store_true")
|
|
||||||
parser.add_argument('--ignore-undefined', help='Suppress any errors related to undefined variables', action="store_true")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if not args.value:
|
|
||||||
if args.unexpand:
|
|
||||||
sys.exit("--unexpand only makes sense with --value")
|
|
||||||
|
|
||||||
if args.flag:
|
|
||||||
sys.exit("--flag only makes sense with --value")
|
|
||||||
|
|
||||||
quiet = args.quiet or args.value
|
|
||||||
with bb.tinfoil.Tinfoil(tracking=True, setup_logging=not quiet) as tinfoil:
|
|
||||||
if args.recipe:
|
|
||||||
tinfoil.prepare(quiet=3 if quiet else 2)
|
|
||||||
d = tinfoil.parse_recipe(args.recipe)
|
|
||||||
else:
|
|
||||||
tinfoil.prepare(quiet=2, config_only=True)
|
|
||||||
d = tinfoil.config_data
|
|
||||||
|
|
||||||
value = None
|
|
||||||
if args.flag:
|
|
||||||
value = d.getVarFlag(args.variable, args.flag, expand=not args.unexpand)
|
|
||||||
if value is None and not args.ignore_undefined:
|
|
||||||
sys.exit(f"The flag '{args.flag}' is not defined for variable '{args.variable}'")
|
|
||||||
else:
|
|
||||||
value = d.getVar(args.variable, expand=not args.unexpand)
|
|
||||||
if value is None and not args.ignore_undefined:
|
|
||||||
sys.exit(f"The variable '{args.variable}' is not defined")
|
|
||||||
if args.value:
|
|
||||||
print(str(value if value is not None else ""))
|
|
||||||
else:
|
|
||||||
bb.data.emit_var(args.variable, d=d, all=True)
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
#! /usr/bin/env python3
|
|
||||||
#
|
|
||||||
# Copyright (C) 2019 Garmin Ltd.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import hashlib
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import pprint
|
|
||||||
import sys
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import warnings
|
|
||||||
import netrc
|
|
||||||
import json
|
|
||||||
warnings.simplefilter("default")
|
|
||||||
|
|
||||||
try:
|
|
||||||
import tqdm
|
|
||||||
ProgressBar = tqdm.tqdm
|
|
||||||
except ImportError:
|
|
||||||
class ProgressBar(object):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, *args, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib'))
|
|
||||||
|
|
||||||
import hashserv
|
|
||||||
import bb.asyncrpc
|
|
||||||
|
|
||||||
DEFAULT_ADDRESS = 'unix://./hashserve.sock'
|
|
||||||
METHOD = 'stress.test.method'
|
|
||||||
|
|
||||||
def print_user(u):
|
|
||||||
print(f"Username: {u['username']}")
|
|
||||||
if "permissions" in u:
|
|
||||||
print("Permissions: " + " ".join(u["permissions"]))
|
|
||||||
if "token" in u:
|
|
||||||
print(f"Token: {u['token']}")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
def handle_get(args, client):
|
|
||||||
result = client.get_taskhash(args.method, args.taskhash, all_properties=True)
|
|
||||||
if not result:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
print(json.dumps(result, sort_keys=True, indent=4))
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def handle_get_outhash(args, client):
|
|
||||||
result = client.get_outhash(args.method, args.outhash, args.taskhash)
|
|
||||||
if not result:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
print(json.dumps(result, sort_keys=True, indent=4))
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def handle_stats(args, client):
|
|
||||||
if args.reset:
|
|
||||||
s = client.reset_stats()
|
|
||||||
else:
|
|
||||||
s = client.get_stats()
|
|
||||||
print(json.dumps(s, sort_keys=True, indent=4))
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def handle_stress(args, client):
|
|
||||||
def thread_main(pbar, lock):
|
|
||||||
nonlocal found_hashes
|
|
||||||
nonlocal missed_hashes
|
|
||||||
nonlocal max_time
|
|
||||||
|
|
||||||
with hashserv.create_client(args.address) as client:
|
|
||||||
for i in range(args.requests):
|
|
||||||
taskhash = hashlib.sha256()
|
|
||||||
taskhash.update(args.taskhash_seed.encode('utf-8'))
|
|
||||||
taskhash.update(str(i).encode('utf-8'))
|
|
||||||
|
|
||||||
start_time = time.perf_counter()
|
|
||||||
l = client.get_unihash(METHOD, taskhash.hexdigest())
|
|
||||||
elapsed = time.perf_counter() - start_time
|
|
||||||
|
|
||||||
with lock:
|
|
||||||
if l:
|
|
||||||
found_hashes += 1
|
|
||||||
else:
|
|
||||||
missed_hashes += 1
|
|
||||||
|
|
||||||
max_time = max(elapsed, max_time)
|
|
||||||
pbar.update()
|
|
||||||
|
|
||||||
max_time = 0
|
|
||||||
found_hashes = 0
|
|
||||||
missed_hashes = 0
|
|
||||||
lock = threading.Lock()
|
|
||||||
total_requests = args.clients * args.requests
|
|
||||||
start_time = time.perf_counter()
|
|
||||||
with ProgressBar(total=total_requests) as pbar:
|
|
||||||
threads = [threading.Thread(target=thread_main, args=(pbar, lock), daemon=False) for _ in range(args.clients)]
|
|
||||||
for t in threads:
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
for t in threads:
|
|
||||||
t.join()
|
|
||||||
|
|
||||||
elapsed = time.perf_counter() - start_time
|
|
||||||
with lock:
|
|
||||||
print("%d requests in %.1fs. %.1f requests per second" % (total_requests, elapsed, total_requests / elapsed))
|
|
||||||
print("Average request time %.8fs" % (elapsed / total_requests))
|
|
||||||
print("Max request time was %.8fs" % max_time)
|
|
||||||
print("Found %d hashes, missed %d" % (found_hashes, missed_hashes))
|
|
||||||
|
|
||||||
if args.report:
|
|
||||||
with ProgressBar(total=args.requests) as pbar:
|
|
||||||
for i in range(args.requests):
|
|
||||||
taskhash = hashlib.sha256()
|
|
||||||
taskhash.update(args.taskhash_seed.encode('utf-8'))
|
|
||||||
taskhash.update(str(i).encode('utf-8'))
|
|
||||||
|
|
||||||
outhash = hashlib.sha256()
|
|
||||||
outhash.update(args.outhash_seed.encode('utf-8'))
|
|
||||||
outhash.update(str(i).encode('utf-8'))
|
|
||||||
|
|
||||||
client.report_unihash(taskhash.hexdigest(), METHOD, outhash.hexdigest(), taskhash.hexdigest())
|
|
||||||
|
|
||||||
with lock:
|
|
||||||
pbar.update()
|
|
||||||
|
|
||||||
def handle_remove(args, client):
|
|
||||||
where = {k: v for k, v in args.where}
|
|
||||||
if where:
|
|
||||||
result = client.remove(where)
|
|
||||||
print("Removed %d row(s)" % (result["count"]))
|
|
||||||
else:
|
|
||||||
print("No query specified")
|
|
||||||
|
|
||||||
def handle_clean_unused(args, client):
|
|
||||||
result = client.clean_unused(args.max_age)
|
|
||||||
print("Removed %d rows" % (result["count"]))
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def handle_refresh_token(args, client):
|
|
||||||
r = client.refresh_token(args.username)
|
|
||||||
print_user(r)
|
|
||||||
|
|
||||||
def handle_set_user_permissions(args, client):
|
|
||||||
r = client.set_user_perms(args.username, args.permissions)
|
|
||||||
print_user(r)
|
|
||||||
|
|
||||||
def handle_get_user(args, client):
|
|
||||||
r = client.get_user(args.username)
|
|
||||||
print_user(r)
|
|
||||||
|
|
||||||
def handle_get_all_users(args, client):
|
|
||||||
users = client.get_all_users()
|
|
||||||
print("{username:20}| {permissions}".format(username="Username", permissions="Permissions"))
|
|
||||||
print(("-" * 20) + "+" + ("-" * 20))
|
|
||||||
for u in users:
|
|
||||||
print("{username:20}| {permissions}".format(username=u["username"], permissions=" ".join(u["permissions"])))
|
|
||||||
|
|
||||||
def handle_new_user(args, client):
|
|
||||||
r = client.new_user(args.username, args.permissions)
|
|
||||||
print_user(r)
|
|
||||||
|
|
||||||
def handle_delete_user(args, client):
|
|
||||||
r = client.delete_user(args.username)
|
|
||||||
print_user(r)
|
|
||||||
|
|
||||||
def handle_get_db_usage(args, client):
|
|
||||||
usage = client.get_db_usage()
|
|
||||||
print(usage)
|
|
||||||
tables = sorted(usage.keys())
|
|
||||||
print("{name:20}| {rows:20}".format(name="Table name", rows="Rows"))
|
|
||||||
print(("-" * 20) + "+" + ("-" * 20))
|
|
||||||
for t in tables:
|
|
||||||
print("{name:20}| {rows:<20}".format(name=t, rows=usage[t]["rows"]))
|
|
||||||
print()
|
|
||||||
|
|
||||||
total_rows = sum(t["rows"] for t in usage.values())
|
|
||||||
print(f"Total rows: {total_rows}")
|
|
||||||
|
|
||||||
def handle_get_db_query_columns(args, client):
|
|
||||||
columns = client.get_db_query_columns()
|
|
||||||
print("\n".join(sorted(columns)))
|
|
||||||
|
|
||||||
def handle_gc_status(args, client):
|
|
||||||
result = client.gc_status()
|
|
||||||
if not result["mark"]:
|
|
||||||
print("No Garbage collection in progress")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
print("Current Mark: %s" % result["mark"])
|
|
||||||
print("Total hashes to keep: %d" % result["keep"])
|
|
||||||
print("Total hashes to remove: %s" % result["remove"])
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def handle_gc_mark(args, client):
|
|
||||||
where = {k: v for k, v in args.where}
|
|
||||||
result = client.gc_mark(args.mark, where)
|
|
||||||
print("New hashes marked: %d" % result["count"])
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def handle_gc_sweep(args, client):
|
|
||||||
result = client.gc_sweep(args.mark)
|
|
||||||
print("Removed %d rows" % result["count"])
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def handle_unihash_exists(args, client):
|
|
||||||
result = client.unihash_exists(args.unihash)
|
|
||||||
if args.quiet:
|
|
||||||
return 0 if result else 1
|
|
||||||
|
|
||||||
print("true" if result else "false")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Hash Equivalence Client')
|
|
||||||
parser.add_argument('--address', default=DEFAULT_ADDRESS, help='Server address (default "%(default)s")')
|
|
||||||
parser.add_argument('--log', default='WARNING', help='Set logging level')
|
|
||||||
parser.add_argument('--login', '-l', metavar="USERNAME", help="Authenticate as USERNAME")
|
|
||||||
parser.add_argument('--password', '-p', metavar="TOKEN", help="Authenticate using token TOKEN")
|
|
||||||
parser.add_argument('--become', '-b', metavar="USERNAME", help="Impersonate user USERNAME (if allowed) when performing actions")
|
|
||||||
parser.add_argument('--no-netrc', '-n', action="store_false", dest="netrc", help="Do not use .netrc")
|
|
||||||
|
|
||||||
subparsers = parser.add_subparsers()
|
|
||||||
|
|
||||||
get_parser = subparsers.add_parser('get', help="Get the unihash for a taskhash")
|
|
||||||
get_parser.add_argument("method", help="Method to query")
|
|
||||||
get_parser.add_argument("taskhash", help="Task hash to query")
|
|
||||||
get_parser.set_defaults(func=handle_get)
|
|
||||||
|
|
||||||
get_outhash_parser = subparsers.add_parser('get-outhash', help="Get output hash information")
|
|
||||||
get_outhash_parser.add_argument("method", help="Method to query")
|
|
||||||
get_outhash_parser.add_argument("outhash", help="Output hash to query")
|
|
||||||
get_outhash_parser.add_argument("taskhash", help="Task hash to query")
|
|
||||||
get_outhash_parser.set_defaults(func=handle_get_outhash)
|
|
||||||
|
|
||||||
stats_parser = subparsers.add_parser('stats', help='Show server stats')
|
|
||||||
stats_parser.add_argument('--reset', action='store_true',
|
|
||||||
help='Reset server stats')
|
|
||||||
stats_parser.set_defaults(func=handle_stats)
|
|
||||||
|
|
||||||
stress_parser = subparsers.add_parser('stress', help='Run stress test')
|
|
||||||
stress_parser.add_argument('--clients', type=int, default=10,
|
|
||||||
help='Number of simultaneous clients')
|
|
||||||
stress_parser.add_argument('--requests', type=int, default=1000,
|
|
||||||
help='Number of requests each client will perform')
|
|
||||||
stress_parser.add_argument('--report', action='store_true',
|
|
||||||
help='Report new hashes')
|
|
||||||
stress_parser.add_argument('--taskhash-seed', default='',
|
|
||||||
help='Include string in taskhash')
|
|
||||||
stress_parser.add_argument('--outhash-seed', default='',
|
|
||||||
help='Include string in outhash')
|
|
||||||
stress_parser.set_defaults(func=handle_stress)
|
|
||||||
|
|
||||||
remove_parser = subparsers.add_parser('remove', help="Remove hash entries")
|
|
||||||
remove_parser.add_argument("--where", "-w", metavar="KEY VALUE", nargs=2, action="append", default=[],
|
|
||||||
help="Remove entries from table where KEY == VALUE")
|
|
||||||
remove_parser.set_defaults(func=handle_remove)
|
|
||||||
|
|
||||||
clean_unused_parser = subparsers.add_parser('clean-unused', help="Remove unused database entries")
|
|
||||||
clean_unused_parser.add_argument("max_age", metavar="SECONDS", type=int, help="Remove unused entries older than SECONDS old")
|
|
||||||
clean_unused_parser.set_defaults(func=handle_clean_unused)
|
|
||||||
|
|
||||||
refresh_token_parser = subparsers.add_parser('refresh-token', help="Refresh auth token")
|
|
||||||
refresh_token_parser.add_argument("--username", "-u", help="Refresh the token for another user (if authorized)")
|
|
||||||
refresh_token_parser.set_defaults(func=handle_refresh_token)
|
|
||||||
|
|
||||||
set_user_perms_parser = subparsers.add_parser('set-user-perms', help="Set new permissions for user")
|
|
||||||
set_user_perms_parser.add_argument("--username", "-u", help="Username", required=True)
|
|
||||||
set_user_perms_parser.add_argument("permissions", metavar="PERM", nargs="*", default=[], help="New permissions")
|
|
||||||
set_user_perms_parser.set_defaults(func=handle_set_user_permissions)
|
|
||||||
|
|
||||||
get_user_parser = subparsers.add_parser('get-user', help="Get user")
|
|
||||||
get_user_parser.add_argument("--username", "-u", help="Username")
|
|
||||||
get_user_parser.set_defaults(func=handle_get_user)
|
|
||||||
|
|
||||||
get_all_users_parser = subparsers.add_parser('get-all-users', help="List all users")
|
|
||||||
get_all_users_parser.set_defaults(func=handle_get_all_users)
|
|
||||||
|
|
||||||
new_user_parser = subparsers.add_parser('new-user', help="Create new user")
|
|
||||||
new_user_parser.add_argument("--username", "-u", help="Username", required=True)
|
|
||||||
new_user_parser.add_argument("permissions", metavar="PERM", nargs="*", default=[], help="New permissions")
|
|
||||||
new_user_parser.set_defaults(func=handle_new_user)
|
|
||||||
|
|
||||||
delete_user_parser = subparsers.add_parser('delete-user', help="Delete user")
|
|
||||||
delete_user_parser.add_argument("--username", "-u", help="Username", required=True)
|
|
||||||
delete_user_parser.set_defaults(func=handle_delete_user)
|
|
||||||
|
|
||||||
db_usage_parser = subparsers.add_parser('get-db-usage', help="Database Usage")
|
|
||||||
db_usage_parser.set_defaults(func=handle_get_db_usage)
|
|
||||||
|
|
||||||
db_query_columns_parser = subparsers.add_parser('get-db-query-columns', help="Show columns that can be used in database queries")
|
|
||||||
db_query_columns_parser.set_defaults(func=handle_get_db_query_columns)
|
|
||||||
|
|
||||||
gc_status_parser = subparsers.add_parser("gc-status", help="Show garbage collection status")
|
|
||||||
gc_status_parser.set_defaults(func=handle_gc_status)
|
|
||||||
|
|
||||||
gc_mark_parser = subparsers.add_parser('gc-mark', help="Mark hashes to be kept for garbage collection")
|
|
||||||
gc_mark_parser.add_argument("mark", help="Mark for this garbage collection operation")
|
|
||||||
gc_mark_parser.add_argument("--where", "-w", metavar="KEY VALUE", nargs=2, action="append", default=[],
|
|
||||||
help="Keep entries in table where KEY == VALUE")
|
|
||||||
gc_mark_parser.set_defaults(func=handle_gc_mark)
|
|
||||||
|
|
||||||
gc_sweep_parser = subparsers.add_parser('gc-sweep', help="Perform garbage collection and delete any entries that are not marked")
|
|
||||||
gc_sweep_parser.add_argument("mark", help="Mark for this garbage collection operation")
|
|
||||||
gc_sweep_parser.set_defaults(func=handle_gc_sweep)
|
|
||||||
|
|
||||||
unihash_exists_parser = subparsers.add_parser('unihash-exists', help="Check if a unihash is known to the server")
|
|
||||||
unihash_exists_parser.add_argument("--quiet", action="store_true", help="Don't print status. Instead, exit with 0 if unihash exists and 1 if it does not")
|
|
||||||
unihash_exists_parser.add_argument("unihash", help="Unihash to check")
|
|
||||||
unihash_exists_parser.set_defaults(func=handle_unihash_exists)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
logger = logging.getLogger('hashserv')
|
|
||||||
|
|
||||||
level = getattr(logging, args.log.upper(), None)
|
|
||||||
if not isinstance(level, int):
|
|
||||||
raise ValueError('Invalid log level: %s' % args.log)
|
|
||||||
|
|
||||||
logger.setLevel(level)
|
|
||||||
console = logging.StreamHandler()
|
|
||||||
console.setLevel(level)
|
|
||||||
logger.addHandler(console)
|
|
||||||
|
|
||||||
login = args.login
|
|
||||||
password = args.password
|
|
||||||
|
|
||||||
if login is None and args.netrc:
|
|
||||||
try:
|
|
||||||
n = netrc.netrc()
|
|
||||||
auth = n.authenticators(args.address)
|
|
||||||
if auth is not None:
|
|
||||||
login, _, password = auth
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
except netrc.NetrcParseError as e:
|
|
||||||
sys.stderr.write(f"Error parsing {e.filename}:{e.lineno}: {e.msg}\n")
|
|
||||||
|
|
||||||
func = getattr(args, 'func', None)
|
|
||||||
if func:
|
|
||||||
try:
|
|
||||||
with hashserv.create_client(args.address, login, password) as client:
|
|
||||||
if args.become:
|
|
||||||
client.become_user(args.become)
|
|
||||||
return func(args, client)
|
|
||||||
except bb.asyncrpc.InvokeError as e:
|
|
||||||
print(f"ERROR: {e}")
|
|
||||||
return 1
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
try:
|
|
||||||
ret = main()
|
|
||||||
except Exception:
|
|
||||||
ret = 1
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
sys.exit(ret)
|
|
||||||
@@ -2,170 +2,66 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2018 Garmin Ltd.
|
# Copyright (C) 2018 Garmin Ltd.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
#
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import argparse
|
import argparse
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.simplefilter("default")
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)),'lib'))
|
||||||
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), "lib"))
|
|
||||||
|
|
||||||
import hashserv
|
import hashserv
|
||||||
from hashserv.server import DEFAULT_ANON_PERMS
|
|
||||||
|
|
||||||
VERSION = "1.0.0"
|
VERSION = "1.0.0"
|
||||||
|
|
||||||
DEFAULT_BIND = "unix://./hashserve.sock"
|
DEFAULT_HOST = ''
|
||||||
|
DEFAULT_PORT = 8686
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(description='HTTP Equivalence Reference Server. Version=%s' % VERSION)
|
||||||
description="Hash Equivalence Reference Server. Version=%s" % VERSION,
|
parser.add_argument('--address', default=DEFAULT_HOST, help='Bind address (default "%(default)s")')
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
parser.add_argument('--port', type=int, default=DEFAULT_PORT, help='Bind port (default %(default)d)')
|
||||||
epilog="""
|
parser.add_argument('--prefix', default='', help='HTTP path prefix (default "%(default)s")')
|
||||||
The bind address may take one of the following formats:
|
parser.add_argument('--database', default='./hashserv.db', help='Database file (default "%(default)s")')
|
||||||
unix://PATH - Bind to unix domain socket at PATH
|
parser.add_argument('--log', default='WARNING', help='Set logging level')
|
||||||
ws://ADDRESS:PORT - Bind to websocket on ADDRESS:PORT
|
|
||||||
ADDRESS:PORT - Bind to raw TCP socket on ADDRESS:PORT
|
|
||||||
|
|
||||||
To bind to all addresses, leave the ADDRESS empty, e.g. "--bind :8686" or
|
|
||||||
"--bind ws://:8686". To bind to a specific IPv6 address, enclose the address in
|
|
||||||
"[]", e.g. "--bind [::1]:8686" or "--bind ws://[::1]:8686"
|
|
||||||
|
|
||||||
Note that the default Anonymous permissions are designed to not break existing
|
|
||||||
server instances when upgrading, but are not particularly secure defaults. If
|
|
||||||
you want to use authentication, it is recommended that you use "--anon-perms
|
|
||||||
@read" to only give anonymous users read access, or "--anon-perms @none" to
|
|
||||||
give un-authenticated users no access at all.
|
|
||||||
|
|
||||||
Setting "--anon-perms @all" or "--anon-perms @user-admin" is not allowed, since
|
|
||||||
this would allow anonymous users to manage all users accounts, which is a bad
|
|
||||||
idea.
|
|
||||||
|
|
||||||
If you are using user authentication, you should run your server in websockets
|
|
||||||
mode with an SSL terminating load balancer in front of it (as this server does
|
|
||||||
not implement SSL). Otherwise all usernames and passwords will be transmitted
|
|
||||||
in the clear. When configured this way, clients can connect using a secure
|
|
||||||
websocket, as in "wss://SERVER:PORT"
|
|
||||||
|
|
||||||
The following permissions are supported by the server:
|
|
||||||
|
|
||||||
@none - No permissions
|
|
||||||
@read - The ability to read equivalent hashes from the server
|
|
||||||
@report - The ability to report equivalent hashes to the server
|
|
||||||
@db-admin - Manage the hash database(s). This includes cleaning the
|
|
||||||
database, removing hashes, etc.
|
|
||||||
@user-admin - The ability to manage user accounts. This includes, creating
|
|
||||||
users, deleting users, resetting login tokens, and assigning
|
|
||||||
permissions.
|
|
||||||
@all - All possible permissions, including any that may be added
|
|
||||||
in the future
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"-b",
|
|
||||||
"--bind",
|
|
||||||
default=os.environ.get("HASHSERVER_BIND", DEFAULT_BIND),
|
|
||||||
help='Bind address (default $HASHSERVER_BIND, "%(default)s")',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-d",
|
|
||||||
"--database",
|
|
||||||
default=os.environ.get("HASHSERVER_DB", "./hashserv.db"),
|
|
||||||
help='Database file (default $HASHSERVER_DB, "%(default)s")',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-l",
|
|
||||||
"--log",
|
|
||||||
default=os.environ.get("HASHSERVER_LOG_LEVEL", "WARNING"),
|
|
||||||
help='Set logging level (default $HASHSERVER_LOG_LEVEL, "%(default)s")',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-u",
|
|
||||||
"--upstream",
|
|
||||||
default=os.environ.get("HASHSERVER_UPSTREAM", None),
|
|
||||||
help="Upstream hashserv to pull hashes from ($HASHSERVER_UPSTREAM)",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-r",
|
|
||||||
"--read-only",
|
|
||||||
action="store_true",
|
|
||||||
help="Disallow write operations from clients ($HASHSERVER_READ_ONLY)",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--db-username",
|
|
||||||
default=os.environ.get("HASHSERVER_DB_USERNAME", None),
|
|
||||||
help="Database username ($HASHSERVER_DB_USERNAME)",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--db-password",
|
|
||||||
default=os.environ.get("HASHSERVER_DB_PASSWORD", None),
|
|
||||||
help="Database password ($HASHSERVER_DB_PASSWORD)",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--anon-perms",
|
|
||||||
metavar="PERM[,PERM[,...]]",
|
|
||||||
default=os.environ.get("HASHSERVER_ANON_PERMS", ",".join(DEFAULT_ANON_PERMS)),
|
|
||||||
help='Permissions to give anonymous users (default $HASHSERVER_ANON_PERMS, "%(default)s")',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--admin-user",
|
|
||||||
default=os.environ.get("HASHSERVER_ADMIN_USER", None),
|
|
||||||
help="Create default admin user with name ADMIN_USER ($HASHSERVER_ADMIN_USER)",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--admin-password",
|
|
||||||
default=os.environ.get("HASHSERVER_ADMIN_PASSWORD", None),
|
|
||||||
help="Create default admin user with password ADMIN_PASSWORD ($HASHSERVER_ADMIN_PASSWORD)",
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
logger = logging.getLogger("hashserv")
|
logger = logging.getLogger('hashserv')
|
||||||
|
|
||||||
level = getattr(logging, args.log.upper(), None)
|
level = getattr(logging, args.log.upper(), None)
|
||||||
if not isinstance(level, int):
|
if not isinstance(level, int):
|
||||||
raise ValueError("Invalid log level: %s (Try ERROR/WARNING/INFO/DEBUG)" % args.log)
|
raise ValueError('Invalid log level: %s' % args.log)
|
||||||
|
|
||||||
logger.setLevel(level)
|
logger.setLevel(level)
|
||||||
console = logging.StreamHandler()
|
console = logging.StreamHandler()
|
||||||
console.setLevel(level)
|
console.setLevel(level)
|
||||||
logger.addHandler(console)
|
logger.addHandler(console)
|
||||||
|
|
||||||
read_only = (os.environ.get("HASHSERVER_READ_ONLY", "0") == "1") or args.read_only
|
db = sqlite3.connect(args.database)
|
||||||
if "," in args.anon_perms:
|
|
||||||
anon_perms = args.anon_perms.split(",")
|
|
||||||
else:
|
|
||||||
anon_perms = args.anon_perms.split()
|
|
||||||
|
|
||||||
server = hashserv.create_server(
|
server = hashserv.create_server((args.address, args.port), db, args.prefix)
|
||||||
args.bind,
|
|
||||||
args.database,
|
|
||||||
upstream=args.upstream,
|
|
||||||
read_only=read_only,
|
|
||||||
db_username=args.db_username,
|
|
||||||
db_password=args.db_password,
|
|
||||||
anon_perms=anon_perms,
|
|
||||||
admin_username=args.admin_user,
|
|
||||||
admin_password=args.admin_password,
|
|
||||||
)
|
|
||||||
server.serve_forever()
|
server.serve_forever()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
try:
|
||||||
ret = main()
|
ret = main()
|
||||||
except Exception:
|
except Exception:
|
||||||
ret = 1
|
ret = 1
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sys.exit(ret)
|
sys.exit(ret)
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,24 @@
|
|||||||
# Copyright (C) 2011 Mentor Graphics Corporation
|
# Copyright (C) 2011 Mentor Graphics Corporation
|
||||||
# Copyright (C) 2011-2015 Intel Corporation
|
# Copyright (C) 2011-2015 Intel Corporation
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
#
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
import warnings
|
import signal
|
||||||
warnings.simplefilter("default")
|
|
||||||
|
|
||||||
bindir = os.path.dirname(__file__)
|
bindir = os.path.dirname(__file__)
|
||||||
topdir = os.path.dirname(bindir)
|
topdir = os.path.dirname(bindir)
|
||||||
@@ -27,6 +36,7 @@ import bb.msg
|
|||||||
logger = bb.msg.logger_create('bitbake-layers', sys.stdout)
|
logger = bb.msg.logger_create('bitbake-layers', sys.stdout)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="BitBake layers utility",
|
description="BitBake layers utility",
|
||||||
epilog="Use %(prog)s <subcommand> --help to get help on a specific command",
|
epilog="Use %(prog)s <subcommand> --help to get help on a specific command",
|
||||||
@@ -52,9 +62,7 @@ def main():
|
|||||||
|
|
||||||
# Need to re-run logger_create with color argument
|
# Need to re-run logger_create with color argument
|
||||||
# (will be the same logger since it has the same name)
|
# (will be the same logger since it has the same name)
|
||||||
bb.msg.logger_create('bitbake-layers', output=sys.stdout,
|
bb.msg.logger_create('bitbake-layers', output=sys.stdout, color=global_args.color)
|
||||||
color=global_args.color,
|
|
||||||
level=logger.getEffectiveLevel())
|
|
||||||
|
|
||||||
plugins = []
|
plugins = []
|
||||||
tinfoil = bb.tinfoil.Tinfoil(tracking=True)
|
tinfoil = bb.tinfoil.Tinfoil(tracking=True)
|
||||||
@@ -68,11 +76,11 @@ def main():
|
|||||||
|
|
||||||
registered = False
|
registered = False
|
||||||
for plugin in plugins:
|
for plugin in plugins:
|
||||||
if hasattr(plugin, 'tinfoil_init'):
|
|
||||||
plugin.tinfoil_init(tinfoil)
|
|
||||||
if hasattr(plugin, 'register_commands'):
|
if hasattr(plugin, 'register_commands'):
|
||||||
registered = True
|
registered = True
|
||||||
plugin.register_commands(subparsers)
|
plugin.register_commands(subparsers)
|
||||||
|
if hasattr(plugin, 'tinfoil_init'):
|
||||||
|
plugin.tinfoil_init(tinfoil)
|
||||||
|
|
||||||
if not registered:
|
if not registered:
|
||||||
logger.error("No commands registered - missing plugins?")
|
logger.error("No commands registered - missing plugins?")
|
||||||
|
|||||||
@@ -1,83 +1,45 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
#
|
|
||||||
# Copyright BitBake Contributors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys,logging
|
import sys,logging
|
||||||
import argparse
|
import optparse
|
||||||
import warnings
|
|
||||||
warnings.simplefilter("default")
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), "lib"))
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)),'lib'))
|
||||||
|
|
||||||
import prserv
|
import prserv
|
||||||
import prserv.serv
|
import prserv.serv
|
||||||
|
|
||||||
VERSION = "1.1.0"
|
__version__="1.0.0"
|
||||||
|
|
||||||
PRHOST_DEFAULT="0.0.0.0"
|
PRHOST_DEFAULT='0.0.0.0'
|
||||||
PRPORT_DEFAULT=8585
|
PRPORT_DEFAULT=8585
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = optparse.OptionParser(
|
||||||
description="BitBake PR Server. Version=%s" % VERSION,
|
version="Bitbake PR Service Core version %s, %%prog version %s" % (prserv.__version__, __version__),
|
||||||
formatter_class=argparse.RawTextHelpFormatter)
|
usage = "%prog < --start | --stop > [options]")
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_option("-f", "--file", help="database filename(default: prserv.sqlite3)", action="store",
|
||||||
"-f",
|
dest="dbfile", type="string", default="prserv.sqlite3")
|
||||||
"--file",
|
parser.add_option("-l", "--log", help="log filename(default: prserv.log)", action="store",
|
||||||
default="prserv.sqlite3",
|
dest="logfile", type="string", default="prserv.log")
|
||||||
help="database filename (default: prserv.sqlite3)",
|
parser.add_option("--loglevel", help="logging level, i.e. CRITICAL, ERROR, WARNING, INFO, DEBUG",
|
||||||
)
|
action = "store", type="string", dest="loglevel", default = "INFO")
|
||||||
parser.add_argument(
|
parser.add_option("--start", help="start daemon",
|
||||||
"-l",
|
action="store_true", dest="start")
|
||||||
"--log",
|
parser.add_option("--stop", help="stop daemon",
|
||||||
default="prserv.log",
|
action="store_true", dest="stop")
|
||||||
help="log filename(default: prserv.log)",
|
parser.add_option("--host", help="ip address to bind", action="store",
|
||||||
)
|
dest="host", type="string", default=PRHOST_DEFAULT)
|
||||||
parser.add_argument(
|
parser.add_option("--port", help="port number(default: 8585)", action="store",
|
||||||
"--loglevel",
|
dest="port", type="int", default=PRPORT_DEFAULT)
|
||||||
default="INFO",
|
|
||||||
help="logging level, i.e. CRITICAL, ERROR, WARNING, INFO, DEBUG",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--start",
|
|
||||||
action="store_true",
|
|
||||||
help="start daemon",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--stop",
|
|
||||||
action="store_true",
|
|
||||||
help="stop daemon",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--host",
|
|
||||||
help="ip address to bind",
|
|
||||||
default=PRHOST_DEFAULT,
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--port",
|
|
||||||
type=int,
|
|
||||||
default=PRPORT_DEFAULT,
|
|
||||||
help="port number (default: 8585)",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-r",
|
|
||||||
"--read-only",
|
|
||||||
action="store_true",
|
|
||||||
help="open database in read-only mode",
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
options, args = parser.parse_args(sys.argv)
|
||||||
prserv.init_logger(os.path.abspath(args.log), args.loglevel)
|
prserv.init_logger(os.path.abspath(options.logfile),options.loglevel)
|
||||||
|
|
||||||
if args.start:
|
if options.start:
|
||||||
ret=prserv.serv.start_daemon(args.file, args.host, args.port, os.path.abspath(args.log), args.read_only)
|
ret=prserv.serv.start_daemon(options.dbfile, options.host, options.port,os.path.abspath(options.logfile))
|
||||||
elif args.stop:
|
elif options.stop:
|
||||||
ret=prserv.serv.stop_daemon(args.host, args.port)
|
ret=prserv.serv.stop_daemon(options.host, options.port)
|
||||||
else:
|
else:
|
||||||
ret=parser.print_help()
|
ret=parser.print_help()
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@@ -2,13 +2,21 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2012 Richard Purdie
|
# Copyright (C) 2012 Richard Purdie
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
#
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys, logging
|
import sys, logging
|
||||||
import warnings
|
|
||||||
warnings.simplefilter("default")
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib'))
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib'))
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
@@ -20,7 +28,6 @@ except RuntimeError as exc:
|
|||||||
sys.exit(str(exc))
|
sys.exit(str(exc))
|
||||||
|
|
||||||
tests = ["bb.tests.codeparser",
|
tests = ["bb.tests.codeparser",
|
||||||
"bb.tests.color",
|
|
||||||
"bb.tests.cooker",
|
"bb.tests.cooker",
|
||||||
"bb.tests.cow",
|
"bb.tests.cow",
|
||||||
"bb.tests.data",
|
"bb.tests.data",
|
||||||
@@ -28,10 +35,7 @@ tests = ["bb.tests.codeparser",
|
|||||||
"bb.tests.fetch",
|
"bb.tests.fetch",
|
||||||
"bb.tests.parse",
|
"bb.tests.parse",
|
||||||
"bb.tests.persist_data",
|
"bb.tests.persist_data",
|
||||||
"bb.tests.runqueue",
|
|
||||||
"bb.tests.siggen",
|
|
||||||
"bb.tests.utils",
|
"bb.tests.utils",
|
||||||
"bb.tests.compression",
|
|
||||||
"hashserv.tests",
|
"hashserv.tests",
|
||||||
"layerindexlib.tests.layerindexobj",
|
"layerindexlib.tests.layerindexobj",
|
||||||
"layerindexlib.tests.restapi",
|
"layerindexlib.tests.restapi",
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
# Copyright (C) 2020 Richard Purdie
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import warnings
|
|
||||||
warnings.simplefilter("default")
|
|
||||||
import logging
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
|
||||||
|
|
||||||
import bb
|
|
||||||
|
|
||||||
bb.utils.check_system_locale()
|
|
||||||
|
|
||||||
# Users shouldn't be running this code directly
|
|
||||||
if len(sys.argv) != 11 or not sys.argv[1].startswith("decafbad"):
|
|
||||||
print("bitbake-server is meant for internal execution by bitbake itself, please don't use it standalone.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
import bb.server.process
|
|
||||||
|
|
||||||
lockfd = int(sys.argv[2])
|
|
||||||
readypipeinfd = int(sys.argv[3])
|
|
||||||
logfile = sys.argv[4]
|
|
||||||
lockname = sys.argv[5]
|
|
||||||
sockname = sys.argv[6]
|
|
||||||
timeout = float(sys.argv[7])
|
|
||||||
profile = bool(int(sys.argv[8]))
|
|
||||||
xmlrpcinterface = (sys.argv[9], int(sys.argv[10]))
|
|
||||||
if xmlrpcinterface[0] == "None":
|
|
||||||
xmlrpcinterface = (None, xmlrpcinterface[1])
|
|
||||||
|
|
||||||
# Replace standard fds with our own
|
|
||||||
with open('/dev/null', 'r') as si:
|
|
||||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
|
||||||
|
|
||||||
so = open(logfile, 'a+')
|
|
||||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
|
||||||
os.dup2(so.fileno(), sys.stderr.fileno())
|
|
||||||
|
|
||||||
# Have stdout and stderr be the same so log output matches chronologically
|
|
||||||
# and there aren't two seperate buffers
|
|
||||||
sys.stderr = sys.stdout
|
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake")
|
|
||||||
# Ensure logging messages get sent to the UI as events
|
|
||||||
handler = bb.event.LogHandler()
|
|
||||||
logger.addHandler(handler)
|
|
||||||
|
|
||||||
bb.server.process.execServer(lockfd, readypipeinfd, lockname, sockname, timeout, xmlrpcinterface, profile)
|
|
||||||
|
|
||||||
@@ -1,14 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
#
|
|
||||||
# Copyright BitBake Contributors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
warnings.simplefilter("default")
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
||||||
from bb import fetch2
|
from bb import fetch2
|
||||||
import logging
|
import logging
|
||||||
@@ -19,12 +13,11 @@ import signal
|
|||||||
import pickle
|
import pickle
|
||||||
import traceback
|
import traceback
|
||||||
import queue
|
import queue
|
||||||
import shlex
|
|
||||||
import subprocess
|
|
||||||
from multiprocessing import Lock
|
from multiprocessing import Lock
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
bb.utils.check_system_locale()
|
if sys.getfilesystemencoding() != "utf-8":
|
||||||
|
sys.exit("Please use a locale setting which supports UTF-8 (such as LANG=en_US.UTF-8).\nPython can't change the filesystem locale after loading so we need a UTF-8 when Python starts or things won't work.")
|
||||||
|
|
||||||
# Users shouldn't be running this code directly
|
# Users shouldn't be running this code directly
|
||||||
if len(sys.argv) != 2 or not sys.argv[1].startswith("decafbad"):
|
if len(sys.argv) != 2 or not sys.argv[1].startswith("decafbad"):
|
||||||
@@ -69,6 +62,7 @@ if 0:
|
|||||||
format_str = "%(levelname)s: %(message)s"
|
format_str = "%(levelname)s: %(message)s"
|
||||||
conlogformat = bb.msg.BBLogFormatter(format_str)
|
conlogformat = bb.msg.BBLogFormatter(format_str)
|
||||||
consolelog = logging.FileHandler(logfilename)
|
consolelog = logging.FileHandler(logfilename)
|
||||||
|
bb.msg.addDefaultlogFilter(consolelog)
|
||||||
consolelog.setFormatter(conlogformat)
|
consolelog.setFormatter(conlogformat)
|
||||||
logger.addHandler(consolelog)
|
logger.addHandler(consolelog)
|
||||||
|
|
||||||
@@ -91,19 +85,19 @@ def worker_fire_prepickled(event):
|
|||||||
worker_thread_exit = False
|
worker_thread_exit = False
|
||||||
|
|
||||||
def worker_flush(worker_queue):
|
def worker_flush(worker_queue):
|
||||||
worker_queue_int = bytearray()
|
worker_queue_int = b""
|
||||||
global worker_pipe, worker_thread_exit
|
global worker_pipe, worker_thread_exit
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
worker_queue_int.extend(worker_queue.get(True, 1))
|
worker_queue_int = worker_queue_int + worker_queue.get(True, 1)
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
while (worker_queue_int or not worker_queue.empty()):
|
while (worker_queue_int or not worker_queue.empty()):
|
||||||
try:
|
try:
|
||||||
(_, ready, _) = select.select([], [worker_pipe], [], 1)
|
(_, ready, _) = select.select([], [worker_pipe], [], 1)
|
||||||
if not worker_queue.empty():
|
if not worker_queue.empty():
|
||||||
worker_queue_int.extend(worker_queue.get())
|
worker_queue_int = worker_queue_int + worker_queue.get()
|
||||||
written = os.write(worker_pipe, worker_queue_int)
|
written = os.write(worker_pipe, worker_queue_int)
|
||||||
worker_queue_int = worker_queue_int[written:]
|
worker_queue_int = worker_queue_int[written:]
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
@@ -121,10 +115,9 @@ def worker_child_fire(event, d):
|
|||||||
|
|
||||||
data = b"<event>" + pickle.dumps(event) + b"</event>"
|
data = b"<event>" + pickle.dumps(event) + b"</event>"
|
||||||
try:
|
try:
|
||||||
with bb.utils.lock_timeout(worker_pipe_lock):
|
worker_pipe_lock.acquire()
|
||||||
while(len(data)):
|
worker_pipe.write(data)
|
||||||
written = worker_pipe.write(data)
|
worker_pipe_lock.release()
|
||||||
data = data[written:]
|
|
||||||
except IOError:
|
except IOError:
|
||||||
sigterm_handler(None, None)
|
sigterm_handler(None, None)
|
||||||
raise
|
raise
|
||||||
@@ -143,59 +136,40 @@ def sigterm_handler(signum, frame):
|
|||||||
os.killpg(0, signal.SIGTERM)
|
os.killpg(0, signal.SIGTERM)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
def fork_off_task(cfg, data, databuilder, workerdata, extraconfigdata, runtask):
|
def fork_off_task(cfg, data, databuilder, workerdata, fn, task, taskname, taskhash, unihash, appends, taskdepdata, extraconfigdata, quieterrors=False, dry_run_exec=False):
|
||||||
|
|
||||||
fn = runtask['fn']
|
|
||||||
task = runtask['task']
|
|
||||||
taskname = runtask['taskname']
|
|
||||||
taskhash = runtask['taskhash']
|
|
||||||
unihash = runtask['unihash']
|
|
||||||
appends = runtask['appends']
|
|
||||||
layername = runtask['layername']
|
|
||||||
taskdepdata = runtask['taskdepdata']
|
|
||||||
quieterrors = runtask['quieterrors']
|
|
||||||
# We need to setup the environment BEFORE the fork, since
|
# We need to setup the environment BEFORE the fork, since
|
||||||
# a fork() or exec*() activates PSEUDO...
|
# a fork() or exec*() activates PSEUDO...
|
||||||
|
|
||||||
envbackup = {}
|
envbackup = {}
|
||||||
fakeroot = False
|
|
||||||
fakeenv = {}
|
fakeenv = {}
|
||||||
umask = None
|
umask = None
|
||||||
|
|
||||||
uid = os.getuid()
|
taskdep = workerdata["taskdeps"][fn]
|
||||||
gid = os.getgid()
|
|
||||||
|
|
||||||
taskdep = runtask['taskdep']
|
|
||||||
if 'umask' in taskdep and taskname in taskdep['umask']:
|
if 'umask' in taskdep and taskname in taskdep['umask']:
|
||||||
umask = taskdep['umask'][taskname]
|
|
||||||
elif workerdata["umask"]:
|
|
||||||
umask = workerdata["umask"]
|
|
||||||
if umask:
|
|
||||||
# umask might come in as a number or text string..
|
# umask might come in as a number or text string..
|
||||||
try:
|
try:
|
||||||
umask = int(umask, 8)
|
umask = int(taskdep['umask'][taskname],8)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
umask = taskdep['umask'][taskname]
|
||||||
|
|
||||||
dry_run = cfg.dry_run or runtask['dry_run']
|
dry_run = cfg.dry_run or dry_run_exec
|
||||||
|
|
||||||
# We can't use the fakeroot environment in a dry run as it possibly hasn't been built
|
# We can't use the fakeroot environment in a dry run as it possibly hasn't been built
|
||||||
if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not dry_run:
|
if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not dry_run:
|
||||||
fakeroot = True
|
envvars = (workerdata["fakerootenv"][fn] or "").split()
|
||||||
envvars = (runtask['fakerootenv'] or "").split()
|
for key, value in (var.split('=') for var in envvars):
|
||||||
for key, value in (var.split('=',1) for var in envvars):
|
|
||||||
envbackup[key] = os.environ.get(key)
|
envbackup[key] = os.environ.get(key)
|
||||||
os.environ[key] = value
|
os.environ[key] = value
|
||||||
fakeenv[key] = value
|
fakeenv[key] = value
|
||||||
|
|
||||||
fakedirs = (runtask['fakerootdirs'] or "").split()
|
fakedirs = (workerdata["fakerootdirs"][fn] or "").split()
|
||||||
for p in fakedirs:
|
for p in fakedirs:
|
||||||
bb.utils.mkdirhier(p)
|
bb.utils.mkdirhier(p)
|
||||||
logger.debug2('Running %s:%s under fakeroot, fakedirs: %s' %
|
logger.debug(2, 'Running %s:%s under fakeroot, fakedirs: %s' %
|
||||||
(fn, taskname, ', '.join(fakedirs)))
|
(fn, taskname, ', '.join(fakedirs)))
|
||||||
else:
|
else:
|
||||||
envvars = (runtask['fakerootnoenv'] or "").split()
|
envvars = (workerdata["fakerootnoenv"][fn] or "").split()
|
||||||
for key, value in (var.split('=',1) for var in envvars):
|
for key, value in (var.split('=') for var in envvars):
|
||||||
envbackup[key] = os.environ.get(key)
|
envbackup[key] = os.environ.get(key)
|
||||||
os.environ[key] = value
|
os.environ[key] = value
|
||||||
fakeenv[key] = value
|
fakeenv[key] = value
|
||||||
@@ -218,6 +192,9 @@ def fork_off_task(cfg, data, databuilder, workerdata, extraconfigdata, runtask):
|
|||||||
global worker_pipe_lock
|
global worker_pipe_lock
|
||||||
pipein.close()
|
pipein.close()
|
||||||
|
|
||||||
|
signal.signal(signal.SIGTERM, sigterm_handler)
|
||||||
|
# Let SIGHUP exit as SIGTERM
|
||||||
|
signal.signal(signal.SIGHUP, sigterm_handler)
|
||||||
bb.utils.signal_on_parent_exit("SIGTERM")
|
bb.utils.signal_on_parent_exit("SIGTERM")
|
||||||
|
|
||||||
# Save out the PID so that the event can include it the
|
# Save out the PID so that the event can include it the
|
||||||
@@ -232,26 +209,19 @@ def fork_off_task(cfg, data, databuilder, workerdata, extraconfigdata, runtask):
|
|||||||
# This ensures signals sent to the controlling terminal like Ctrl+C
|
# This ensures signals sent to the controlling terminal like Ctrl+C
|
||||||
# don't stop the child processes.
|
# don't stop the child processes.
|
||||||
os.setsid()
|
os.setsid()
|
||||||
|
# No stdin
|
||||||
|
newsi = os.open(os.devnull, os.O_RDWR)
|
||||||
|
os.dup2(newsi, sys.stdin.fileno())
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, sigterm_handler)
|
if umask:
|
||||||
# Let SIGHUP exit as SIGTERM
|
|
||||||
signal.signal(signal.SIGHUP, sigterm_handler)
|
|
||||||
|
|
||||||
# No stdin & stdout
|
|
||||||
# stdout is used as a status report channel and must not be used by child processes.
|
|
||||||
dumbio = os.open(os.devnull, os.O_RDWR)
|
|
||||||
os.dup2(dumbio, sys.stdin.fileno())
|
|
||||||
os.dup2(dumbio, sys.stdout.fileno())
|
|
||||||
|
|
||||||
if umask is not None:
|
|
||||||
os.umask(umask)
|
os.umask(umask)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
bb_cache = bb.cache.NoCache(databuilder)
|
||||||
(realfn, virtual, mc) = bb.cache.virtualfn2realfn(fn)
|
(realfn, virtual, mc) = bb.cache.virtualfn2realfn(fn)
|
||||||
the_data = databuilder.mcdata[mc]
|
the_data = databuilder.mcdata[mc]
|
||||||
the_data.setVar("BB_WORKERCONTEXT", "1")
|
the_data.setVar("BB_WORKERCONTEXT", "1")
|
||||||
the_data.setVar("BB_TASKDEPDATA", taskdepdata)
|
the_data.setVar("BB_TASKDEPDATA", taskdepdata)
|
||||||
the_data.setVar('BB_CURRENTTASK', taskname.replace("do_", ""))
|
|
||||||
if cfg.limited_deps:
|
if cfg.limited_deps:
|
||||||
the_data.setVar("BB_LIMITEDDEPS", "1")
|
the_data.setVar("BB_LIMITEDDEPS", "1")
|
||||||
the_data.setVar("BUILDNAME", workerdata["buildname"])
|
the_data.setVar("BUILDNAME", workerdata["buildname"])
|
||||||
@@ -261,24 +231,14 @@ def fork_off_task(cfg, data, databuilder, workerdata, extraconfigdata, runtask):
|
|||||||
the_data.setVar(varname, value)
|
the_data.setVar(varname, value)
|
||||||
|
|
||||||
bb.parse.siggen.set_taskdata(workerdata["sigdata"])
|
bb.parse.siggen.set_taskdata(workerdata["sigdata"])
|
||||||
if "newhashes" in workerdata:
|
|
||||||
bb.parse.siggen.set_taskhashes(workerdata["newhashes"])
|
|
||||||
ret = 0
|
ret = 0
|
||||||
|
|
||||||
the_data = databuilder.parseRecipe(fn, appends, layername)
|
the_data = bb_cache.loadDataFull(fn, appends)
|
||||||
the_data.setVar('BB_TASKHASH', taskhash)
|
the_data.setVar('BB_TASKHASH', taskhash)
|
||||||
the_data.setVar('BB_UNIHASH', unihash)
|
the_data.setVar('BB_UNIHASH', unihash)
|
||||||
bb.parse.siggen.setup_datacache_from_datastore(fn, the_data)
|
|
||||||
|
|
||||||
bb.utils.set_process_name("%s:%s" % (the_data.getVar("PN"), taskname.replace("do_", "")))
|
bb.utils.set_process_name("%s:%s" % (the_data.getVar("PN"), taskname.replace("do_", "")))
|
||||||
|
|
||||||
if not bb.utils.to_boolean(the_data.getVarFlag(taskname, 'network')):
|
|
||||||
if bb.utils.is_local_uid(uid):
|
|
||||||
logger.debug("Attempting to disable network for %s" % taskname)
|
|
||||||
bb.utils.disable_network(uid, gid)
|
|
||||||
else:
|
|
||||||
logger.debug("Skipping disable network for %s since %s is not a local uid." % (taskname, uid))
|
|
||||||
|
|
||||||
# exported_vars() returns a generator which *cannot* be passed to os.environ.update()
|
# exported_vars() returns a generator which *cannot* be passed to os.environ.update()
|
||||||
# successfully. We also need to unset anything from the environment which shouldn't be there
|
# successfully. We also need to unset anything from the environment which shouldn't be there
|
||||||
exports = bb.data.exported_vars(the_data)
|
exports = bb.data.exported_vars(the_data)
|
||||||
@@ -307,20 +267,10 @@ def fork_off_task(cfg, data, databuilder, workerdata, extraconfigdata, runtask):
|
|||||||
if not quieterrors:
|
if not quieterrors:
|
||||||
logger.critical(traceback.format_exc())
|
logger.critical(traceback.format_exc())
|
||||||
os._exit(1)
|
os._exit(1)
|
||||||
|
|
||||||
sys.stdout.flush()
|
|
||||||
sys.stderr.flush()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return 0
|
return 0
|
||||||
try:
|
return bb.build.exec_task(fn, taskname, the_data, cfg.profile)
|
||||||
ret = bb.build.exec_task(fn, taskname, the_data, cfg.profile)
|
|
||||||
finally:
|
|
||||||
if fakeroot:
|
|
||||||
fakerootcmd = shlex.split(the_data.getVar("FAKEROOTCMD"))
|
|
||||||
subprocess.run(fakerootcmd + ['-S'], check=True, stdout=subprocess.PIPE)
|
|
||||||
return ret
|
|
||||||
except:
|
except:
|
||||||
os._exit(1)
|
os._exit(1)
|
||||||
if not profiling:
|
if not profiling:
|
||||||
@@ -352,12 +302,12 @@ class runQueueWorkerPipe():
|
|||||||
if pipeout:
|
if pipeout:
|
||||||
pipeout.close()
|
pipeout.close()
|
||||||
bb.utils.nonblockingfd(self.input)
|
bb.utils.nonblockingfd(self.input)
|
||||||
self.queue = bytearray()
|
self.queue = b""
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
start = len(self.queue)
|
start = len(self.queue)
|
||||||
try:
|
try:
|
||||||
self.queue.extend(self.input.read(102400) or b"")
|
self.queue = self.queue + (self.input.read(102400) or b"")
|
||||||
except (OSError, IOError) as e:
|
except (OSError, IOError) as e:
|
||||||
if e.errno != errno.EAGAIN:
|
if e.errno != errno.EAGAIN:
|
||||||
raise
|
raise
|
||||||
@@ -365,9 +315,7 @@ class runQueueWorkerPipe():
|
|||||||
end = len(self.queue)
|
end = len(self.queue)
|
||||||
index = self.queue.find(b"</event>")
|
index = self.queue.find(b"</event>")
|
||||||
while index != -1:
|
while index != -1:
|
||||||
msg = self.queue[:index+8]
|
worker_fire_prepickled(self.queue[:index+8])
|
||||||
assert msg.startswith(b"<event>") and msg.count(b"<event>") == 1
|
|
||||||
worker_fire_prepickled(msg)
|
|
||||||
self.queue = self.queue[index+8:]
|
self.queue = self.queue[index+8:]
|
||||||
index = self.queue.find(b"</event>")
|
index = self.queue.find(b"</event>")
|
||||||
return (end > start)
|
return (end > start)
|
||||||
@@ -385,7 +333,7 @@ class BitbakeWorker(object):
|
|||||||
def __init__(self, din):
|
def __init__(self, din):
|
||||||
self.input = din
|
self.input = din
|
||||||
bb.utils.nonblockingfd(self.input)
|
bb.utils.nonblockingfd(self.input)
|
||||||
self.queue = bytearray()
|
self.queue = b""
|
||||||
self.cookercfg = None
|
self.cookercfg = None
|
||||||
self.databuilder = None
|
self.databuilder = None
|
||||||
self.data = None
|
self.data = None
|
||||||
@@ -419,14 +367,13 @@ class BitbakeWorker(object):
|
|||||||
if len(r) == 0:
|
if len(r) == 0:
|
||||||
# EOF on pipe, server must have terminated
|
# EOF on pipe, server must have terminated
|
||||||
self.sigterm_exception(signal.SIGTERM, None)
|
self.sigterm_exception(signal.SIGTERM, None)
|
||||||
self.queue.extend(r)
|
self.queue = self.queue + r
|
||||||
except (OSError, IOError):
|
except (OSError, IOError):
|
||||||
pass
|
pass
|
||||||
if len(self.queue):
|
if len(self.queue):
|
||||||
self.handle_item(b"cookerconfig", self.handle_cookercfg)
|
self.handle_item(b"cookerconfig", self.handle_cookercfg)
|
||||||
self.handle_item(b"extraconfigdata", self.handle_extraconfigdata)
|
self.handle_item(b"extraconfigdata", self.handle_extraconfigdata)
|
||||||
self.handle_item(b"workerdata", self.handle_workerdata)
|
self.handle_item(b"workerdata", self.handle_workerdata)
|
||||||
self.handle_item(b"newtaskhashes", self.handle_newtaskhashes)
|
|
||||||
self.handle_item(b"runtask", self.handle_runtask)
|
self.handle_item(b"runtask", self.handle_runtask)
|
||||||
self.handle_item(b"finishnow", self.handle_finishnow)
|
self.handle_item(b"finishnow", self.handle_finishnow)
|
||||||
self.handle_item(b"ping", self.handle_ping)
|
self.handle_item(b"ping", self.handle_ping)
|
||||||
@@ -439,35 +386,19 @@ class BitbakeWorker(object):
|
|||||||
while self.process_waitpid():
|
while self.process_waitpid():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
def handle_item(self, item, func):
|
def handle_item(self, item, func):
|
||||||
opening_tag = b"<" + item + b">"
|
if self.queue.startswith(b"<" + item + b">"):
|
||||||
if not self.queue.startswith(opening_tag):
|
index = self.queue.find(b"</" + item + b">")
|
||||||
return
|
while index != -1:
|
||||||
|
func(self.queue[(len(item) + 2):index])
|
||||||
tag_len = len(opening_tag)
|
self.queue = self.queue[(index + len(item) + 3):]
|
||||||
if len(self.queue) < tag_len + 4:
|
index = self.queue.find(b"</" + item + b">")
|
||||||
# we need to receive more data
|
|
||||||
return
|
|
||||||
header = self.queue[tag_len:tag_len + 4]
|
|
||||||
payload_len = int.from_bytes(header, 'big')
|
|
||||||
# closing tag has length (tag_len + 1)
|
|
||||||
if len(self.queue) < tag_len * 2 + 1 + payload_len:
|
|
||||||
# we need to receive more data
|
|
||||||
return
|
|
||||||
|
|
||||||
index = self.queue.find(b"</" + item + b">")
|
|
||||||
if index != -1:
|
|
||||||
try:
|
|
||||||
func(self.queue[(tag_len + 4):index])
|
|
||||||
except pickle.UnpicklingError:
|
|
||||||
workerlog_write("Unable to unpickle data: %s\n" % ":".join("{:02x}".format(c) for c in self.queue))
|
|
||||||
raise
|
|
||||||
self.queue = self.queue[(index + len(b"</") + len(item) + len(b">")):]
|
|
||||||
|
|
||||||
def handle_cookercfg(self, data):
|
def handle_cookercfg(self, data):
|
||||||
self.cookercfg = pickle.loads(data)
|
self.cookercfg = pickle.loads(data)
|
||||||
self.databuilder = bb.cookerdata.CookerDataBuilder(self.cookercfg, worker=True)
|
self.databuilder = bb.cookerdata.CookerDataBuilder(self.cookercfg, worker=True)
|
||||||
self.databuilder.parseBaseConfiguration(worker=True)
|
self.databuilder.parseBaseConfiguration()
|
||||||
self.data = self.databuilder.data
|
self.data = self.databuilder.data
|
||||||
|
|
||||||
def handle_extraconfigdata(self, data):
|
def handle_extraconfigdata(self, data):
|
||||||
@@ -475,17 +406,12 @@ class BitbakeWorker(object):
|
|||||||
|
|
||||||
def handle_workerdata(self, data):
|
def handle_workerdata(self, data):
|
||||||
self.workerdata = pickle.loads(data)
|
self.workerdata = pickle.loads(data)
|
||||||
bb.build.verboseShellLogging = self.workerdata["build_verbose_shell"]
|
bb.msg.loggerDefaultDebugLevel = self.workerdata["logdefaultdebug"]
|
||||||
bb.build.verboseStdoutLogging = self.workerdata["build_verbose_stdout"]
|
bb.msg.loggerDefaultVerbose = self.workerdata["logdefaultverbose"]
|
||||||
bb.msg.loggerDefaultLogLevel = self.workerdata["logdefaultlevel"]
|
bb.msg.loggerVerboseLogs = self.workerdata["logdefaultverboselogs"]
|
||||||
bb.msg.loggerDefaultDomains = self.workerdata["logdefaultdomain"]
|
bb.msg.loggerDefaultDomains = self.workerdata["logdefaultdomain"]
|
||||||
for mc in self.databuilder.mcdata:
|
for mc in self.databuilder.mcdata:
|
||||||
self.databuilder.mcdata[mc].setVar("PRSERV_HOST", self.workerdata["prhost"])
|
self.databuilder.mcdata[mc].setVar("PRSERV_HOST", self.workerdata["prhost"])
|
||||||
self.databuilder.mcdata[mc].setVar("BB_HASHSERVE", self.workerdata["hashservaddr"])
|
|
||||||
self.databuilder.mcdata[mc].setVar("__bbclasstype", "recipe")
|
|
||||||
|
|
||||||
def handle_newtaskhashes(self, data):
|
|
||||||
self.workerdata["newhashes"] = pickle.loads(data)
|
|
||||||
|
|
||||||
def handle_ping(self, _):
|
def handle_ping(self, _):
|
||||||
workerlog_write("Handling ping\n")
|
workerlog_write("Handling ping\n")
|
||||||
@@ -500,15 +426,11 @@ class BitbakeWorker(object):
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
def handle_runtask(self, data):
|
def handle_runtask(self, data):
|
||||||
runtask = pickle.loads(data)
|
fn, task, taskname, taskhash, unihash, quieterrors, appends, taskdepdata, dry_run_exec = pickle.loads(data)
|
||||||
|
|
||||||
fn = runtask['fn']
|
|
||||||
task = runtask['task']
|
|
||||||
taskname = runtask['taskname']
|
|
||||||
|
|
||||||
workerlog_write("Handling runtask %s %s %s\n" % (task, fn, taskname))
|
workerlog_write("Handling runtask %s %s %s\n" % (task, fn, taskname))
|
||||||
|
|
||||||
pid, pipein, pipeout = fork_off_task(self.cookercfg, self.data, self.databuilder, self.workerdata, self.extraconfigdata, runtask)
|
pid, pipein, pipeout = fork_off_task(self.cookercfg, self.data, self.databuilder, self.workerdata, fn, task, taskname, taskhash, unihash, appends, taskdepdata, self.extraconfigdata, quieterrors, dry_run_exec)
|
||||||
|
|
||||||
self.build_pids[pid] = task
|
self.build_pids[pid] = task
|
||||||
self.build_pipes[pid] = runQueueWorkerPipe(pipein, pipeout)
|
self.build_pipes[pid] = runQueueWorkerPipe(pipein, pipeout)
|
||||||
|
|
||||||
@@ -572,11 +494,9 @@ except BaseException as e:
|
|||||||
import traceback
|
import traceback
|
||||||
sys.stderr.write(traceback.format_exc())
|
sys.stderr.write(traceback.format_exc())
|
||||||
sys.stderr.write(str(e))
|
sys.stderr.write(str(e))
|
||||||
finally:
|
|
||||||
worker_thread_exit = True
|
|
||||||
worker_thread.join()
|
|
||||||
|
|
||||||
workerlog_write("exiting")
|
worker_thread_exit = True
|
||||||
if not normalexit:
|
worker_thread.join()
|
||||||
sys.exit(1)
|
|
||||||
|
workerlog_write("exitting")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
531
bitbake/bin/bitdoc
Executable file
531
bitbake/bin/bitdoc
Executable file
@@ -0,0 +1,531 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# ex:ts=4:sw=4:sts=4:et
|
||||||
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 2005 Holger Hans Peter Freyther
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
import optparse, os, sys
|
||||||
|
|
||||||
|
# bitbake
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__), 'lib'))
|
||||||
|
import bb
|
||||||
|
import bb.parse
|
||||||
|
from string import split, join
|
||||||
|
|
||||||
|
__version__ = "0.0.2"
|
||||||
|
|
||||||
|
class HTMLFormatter:
|
||||||
|
"""
|
||||||
|
Simple class to help to generate some sort of HTML files. It is
|
||||||
|
quite inferior solution compared to docbook, gtkdoc, doxygen but it
|
||||||
|
should work for now.
|
||||||
|
We've a global introduction site (index.html) and then one site for
|
||||||
|
the list of keys (alphabetical sorted) and one for the list of groups,
|
||||||
|
one site for each key with links to the relations and groups.
|
||||||
|
|
||||||
|
index.html
|
||||||
|
all_keys.html
|
||||||
|
all_groups.html
|
||||||
|
groupNAME.html
|
||||||
|
keyNAME.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
def replace(self, text, *pairs):
|
||||||
|
"""
|
||||||
|
From pydoc... almost identical at least
|
||||||
|
"""
|
||||||
|
while pairs:
|
||||||
|
(a, b) = pairs[0]
|
||||||
|
text = join(split(text, a), b)
|
||||||
|
pairs = pairs[1:]
|
||||||
|
return text
|
||||||
|
def escape(self, text):
|
||||||
|
"""
|
||||||
|
Escape string to be conform HTML
|
||||||
|
"""
|
||||||
|
return self.replace(text,
|
||||||
|
('&', '&'),
|
||||||
|
('<', '<' ),
|
||||||
|
('>', '>' ) )
|
||||||
|
def createNavigator(self):
|
||||||
|
"""
|
||||||
|
Create the navgiator
|
||||||
|
"""
|
||||||
|
return """<table class="navigation" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2">
|
||||||
|
<tr valign="middle">
|
||||||
|
<td><a accesskey="g" href="index.html">Home</a></td>
|
||||||
|
<td><a accesskey="n" href="all_groups.html">Groups</a></td>
|
||||||
|
<td><a accesskey="u" href="all_keys.html">Keys</a></td>
|
||||||
|
</tr></table>
|
||||||
|
"""
|
||||||
|
|
||||||
|
def relatedKeys(self, item):
|
||||||
|
"""
|
||||||
|
Create HTML to link to foreign keys
|
||||||
|
"""
|
||||||
|
|
||||||
|
if len(item.related()) == 0:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
txt = "<p><b>See also:</b><br>"
|
||||||
|
txts = []
|
||||||
|
for it in item.related():
|
||||||
|
txts.append("""<a href="key%(it)s.html">%(it)s</a>""" % vars() )
|
||||||
|
|
||||||
|
return txt + ",".join(txts)
|
||||||
|
|
||||||
|
def groups(self, item):
|
||||||
|
"""
|
||||||
|
Create HTML to link to related groups
|
||||||
|
"""
|
||||||
|
|
||||||
|
if len(item.groups()) == 0:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
txt = "<p><b>See also:</b><br>"
|
||||||
|
txts = []
|
||||||
|
for group in item.groups():
|
||||||
|
txts.append( """<a href="group%s.html">%s</a> """ % (group, group) )
|
||||||
|
|
||||||
|
return txt + ",".join(txts)
|
||||||
|
|
||||||
|
|
||||||
|
def createKeySite(self, item):
|
||||||
|
"""
|
||||||
|
Create a site for a key. It contains the header/navigator, a heading,
|
||||||
|
the description, links to related keys and to the groups.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<html><head><title>Key %s</title></head>
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css">
|
||||||
|
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||||||
|
%s
|
||||||
|
<h2><span class="refentrytitle">%s</span></h2>
|
||||||
|
|
||||||
|
<div class="refsynopsisdiv">
|
||||||
|
<h2>Synopsis</h2>
|
||||||
|
<p>
|
||||||
|
%s
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="refsynopsisdiv">
|
||||||
|
<h2>Related Keys</h2>
|
||||||
|
<p>
|
||||||
|
%s
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="refsynopsisdiv">
|
||||||
|
<h2>Groups</h2>
|
||||||
|
<p>
|
||||||
|
%s
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
""" % (item.name(), self.createNavigator(), item.name(),
|
||||||
|
self.escape(item.description()), self.relatedKeys(item), self.groups(item))
|
||||||
|
|
||||||
|
def createGroupsSite(self, doc):
|
||||||
|
"""
|
||||||
|
Create the Group Overview site
|
||||||
|
"""
|
||||||
|
|
||||||
|
groups = ""
|
||||||
|
sorted_groups = sorted(doc.groups())
|
||||||
|
for group in sorted_groups:
|
||||||
|
groups += """<a href="group%s.html">%s</a><br>""" % (group, group)
|
||||||
|
|
||||||
|
return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<html><head><title>Group overview</title></head>
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css">
|
||||||
|
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||||||
|
%s
|
||||||
|
<h2>Available Groups</h2>
|
||||||
|
%s
|
||||||
|
</body>
|
||||||
|
""" % (self.createNavigator(), groups)
|
||||||
|
|
||||||
|
def createIndex(self):
|
||||||
|
"""
|
||||||
|
Create the index file
|
||||||
|
"""
|
||||||
|
|
||||||
|
return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<html><head><title>Bitbake Documentation</title></head>
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css">
|
||||||
|
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||||||
|
%s
|
||||||
|
<h2>Documentation Entrance</h2>
|
||||||
|
<a href="all_groups.html">All available groups</a><br>
|
||||||
|
<a href="all_keys.html">All available keys</a><br>
|
||||||
|
</body>
|
||||||
|
""" % self.createNavigator()
|
||||||
|
|
||||||
|
def createKeysSite(self, doc):
|
||||||
|
"""
|
||||||
|
Create Overview of all avilable keys
|
||||||
|
"""
|
||||||
|
keys = ""
|
||||||
|
sorted_keys = sorted(doc.doc_keys())
|
||||||
|
for key in sorted_keys:
|
||||||
|
keys += """<a href="key%s.html">%s</a><br>""" % (key, key)
|
||||||
|
|
||||||
|
return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<html><head><title>Key overview</title></head>
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css">
|
||||||
|
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||||||
|
%s
|
||||||
|
<h2>Available Keys</h2>
|
||||||
|
%s
|
||||||
|
</body>
|
||||||
|
""" % (self.createNavigator(), keys)
|
||||||
|
|
||||||
|
def createGroupSite(self, gr, items, _description = None):
|
||||||
|
"""
|
||||||
|
Create a site for a group:
|
||||||
|
Group the name of the group, items contain the name of the keys
|
||||||
|
inside this group
|
||||||
|
"""
|
||||||
|
groups = ""
|
||||||
|
description = ""
|
||||||
|
|
||||||
|
# create a section with the group descriptions
|
||||||
|
if _description:
|
||||||
|
description += "<h2 Description of Grozp %s</h2>" % gr
|
||||||
|
description += _description
|
||||||
|
|
||||||
|
items.sort(lambda x, y:cmp(x.name(), y.name()))
|
||||||
|
for group in items:
|
||||||
|
groups += """<a href="key%s.html">%s</a><br>""" % (group.name(), group.name())
|
||||||
|
|
||||||
|
return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<html><head><title>Group %s</title></head>
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css">
|
||||||
|
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||||||
|
%s
|
||||||
|
%s
|
||||||
|
<div class="refsynopsisdiv">
|
||||||
|
<h2>Keys in Group %s</h2>
|
||||||
|
<pre class="synopsis">
|
||||||
|
%s
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
""" % (gr, self.createNavigator(), description, gr, groups)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def createCSS(self):
|
||||||
|
"""
|
||||||
|
Create the CSS file
|
||||||
|
"""
|
||||||
|
return """.synopsis, .classsynopsis
|
||||||
|
{
|
||||||
|
background: #eeeeee;
|
||||||
|
border: solid 1px #aaaaaa;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
.programlisting
|
||||||
|
{
|
||||||
|
background: #eeeeff;
|
||||||
|
border: solid 1px #aaaaff;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
.variablelist
|
||||||
|
{
|
||||||
|
padding: 4px;
|
||||||
|
margin-left: 3em;
|
||||||
|
}
|
||||||
|
.variablelist td:first-child
|
||||||
|
{
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
table.navigation
|
||||||
|
{
|
||||||
|
background: #ffeeee;
|
||||||
|
border: solid 1px #ffaaaa;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.navigation a
|
||||||
|
{
|
||||||
|
color: #770000;
|
||||||
|
}
|
||||||
|
.navigation a:visited
|
||||||
|
{
|
||||||
|
color: #550000;
|
||||||
|
}
|
||||||
|
.navigation .title
|
||||||
|
{
|
||||||
|
font-size: 200%;
|
||||||
|
}
|
||||||
|
div.refnamediv
|
||||||
|
{
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
div.gallery-float
|
||||||
|
{
|
||||||
|
float: left;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
div.gallery-float img
|
||||||
|
{
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
div.gallery-spacer
|
||||||
|
{
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
a
|
||||||
|
{
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover
|
||||||
|
{
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #FF0000;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentationItem:
|
||||||
|
"""
|
||||||
|
A class to hold information about a configuration
|
||||||
|
item. It contains the key name, description, a list of related names,
|
||||||
|
and the group this item is contained in.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._groups = []
|
||||||
|
self._related = []
|
||||||
|
self._name = ""
|
||||||
|
self._desc = ""
|
||||||
|
|
||||||
|
def groups(self):
|
||||||
|
return self._groups
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
def description(self):
|
||||||
|
return self._desc
|
||||||
|
|
||||||
|
def related(self):
|
||||||
|
return self._related
|
||||||
|
|
||||||
|
def setName(self, name):
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
def setDescription(self, desc):
|
||||||
|
self._desc = desc
|
||||||
|
|
||||||
|
def addGroup(self, group):
|
||||||
|
self._groups.append(group)
|
||||||
|
|
||||||
|
def addRelation(self, relation):
|
||||||
|
self._related.append(relation)
|
||||||
|
|
||||||
|
def sort(self):
|
||||||
|
self._related.sort()
|
||||||
|
self._groups.sort()
|
||||||
|
|
||||||
|
|
||||||
|
class Documentation:
|
||||||
|
"""
|
||||||
|
Holds the documentation... with mappings from key to items...
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.__keys = {}
|
||||||
|
self.__groups = {}
|
||||||
|
|
||||||
|
def insert_doc_item(self, item):
|
||||||
|
"""
|
||||||
|
Insert the Doc Item into the internal list
|
||||||
|
of representation
|
||||||
|
"""
|
||||||
|
item.sort()
|
||||||
|
self.__keys[item.name()] = item
|
||||||
|
|
||||||
|
for group in item.groups():
|
||||||
|
if not group in self.__groups:
|
||||||
|
self.__groups[group] = []
|
||||||
|
self.__groups[group].append(item)
|
||||||
|
self.__groups[group].sort()
|
||||||
|
|
||||||
|
|
||||||
|
def doc_item(self, key):
|
||||||
|
"""
|
||||||
|
Return the DocumentationInstance describing the key
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.__keys[key]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def doc_keys(self):
|
||||||
|
"""
|
||||||
|
Return the documented KEYS (names)
|
||||||
|
"""
|
||||||
|
return self.__keys.keys()
|
||||||
|
|
||||||
|
def groups(self):
|
||||||
|
"""
|
||||||
|
Return the names of available groups
|
||||||
|
"""
|
||||||
|
return self.__groups.keys()
|
||||||
|
|
||||||
|
def group_content(self, group_name):
|
||||||
|
"""
|
||||||
|
Return a list of keys/names that are in a specefic
|
||||||
|
group or the empty list
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.__groups[group_name]
|
||||||
|
except KeyError:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def parse_cmdline(args):
|
||||||
|
"""
|
||||||
|
Parse the CMD line and return the result as a n-tuple
|
||||||
|
"""
|
||||||
|
|
||||||
|
parser = optparse.OptionParser( version = "Bitbake Documentation Tool Core version %s, %%prog version %s" % (bb.__version__, __version__))
|
||||||
|
usage = """%prog [options]
|
||||||
|
|
||||||
|
Create a set of html pages (documentation) for a bitbake.conf....
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Add the needed options
|
||||||
|
parser.add_option( "-c", "--config", help = "Use the specified configuration file as source",
|
||||||
|
action = "store", dest = "config", default = os.path.join("conf", "documentation.conf") )
|
||||||
|
|
||||||
|
parser.add_option( "-o", "--output", help = "Output directory for html files",
|
||||||
|
action = "store", dest = "output", default = "html/" )
|
||||||
|
|
||||||
|
parser.add_option( "-D", "--debug", help = "Increase the debug level",
|
||||||
|
action = "count", dest = "debug", default = 0 )
|
||||||
|
|
||||||
|
parser.add_option( "-v", "--verbose", help = "output more chit-char to the terminal",
|
||||||
|
action = "store_true", dest = "verbose", default = False )
|
||||||
|
|
||||||
|
options, args = parser.parse_args( sys.argv )
|
||||||
|
|
||||||
|
bb.msg.init_msgconfig(options.verbose, options.debug)
|
||||||
|
|
||||||
|
return options.config, options.output
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
The main Method
|
||||||
|
"""
|
||||||
|
|
||||||
|
(config_file, output_dir) = parse_cmdline( sys.argv )
|
||||||
|
|
||||||
|
# right to let us load the file now
|
||||||
|
try:
|
||||||
|
documentation = bb.parse.handle( config_file, bb.data.init() )
|
||||||
|
except IOError:
|
||||||
|
bb.fatal( "Unable to open %s" % config_file )
|
||||||
|
except bb.parse.ParseError:
|
||||||
|
bb.fatal( "Unable to parse %s" % config_file )
|
||||||
|
|
||||||
|
if isinstance(documentation, dict):
|
||||||
|
documentation = documentation[""]
|
||||||
|
|
||||||
|
# Assuming we've the file loaded now, we will initialize the 'tree'
|
||||||
|
doc = Documentation()
|
||||||
|
|
||||||
|
# defined states
|
||||||
|
state_begin = 0
|
||||||
|
state_see = 1
|
||||||
|
state_group = 2
|
||||||
|
|
||||||
|
for key in bb.data.keys(documentation):
|
||||||
|
data = documentation.getVarFlag(key, "doc", False)
|
||||||
|
if not data:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# The Documentation now starts
|
||||||
|
doc_ins = DocumentationItem()
|
||||||
|
doc_ins.setName(key)
|
||||||
|
|
||||||
|
|
||||||
|
tokens = data.split(' ')
|
||||||
|
state = state_begin
|
||||||
|
string= ""
|
||||||
|
for token in tokens:
|
||||||
|
token = token.strip(',')
|
||||||
|
|
||||||
|
if not state == state_see and token == "@see":
|
||||||
|
state = state_see
|
||||||
|
continue
|
||||||
|
elif not state == state_group and token == "@group":
|
||||||
|
state = state_group
|
||||||
|
continue
|
||||||
|
|
||||||
|
if state == state_begin:
|
||||||
|
string += " %s" % token
|
||||||
|
elif state == state_see:
|
||||||
|
doc_ins.addRelation(token)
|
||||||
|
elif state == state_group:
|
||||||
|
doc_ins.addGroup(token)
|
||||||
|
|
||||||
|
# set the description
|
||||||
|
doc_ins.setDescription(string)
|
||||||
|
doc.insert_doc_item(doc_ins)
|
||||||
|
|
||||||
|
# let us create the HTML now
|
||||||
|
bb.utils.mkdirhier(output_dir)
|
||||||
|
os.chdir(output_dir)
|
||||||
|
|
||||||
|
# Let us create the sites now. We do it in the following order
|
||||||
|
# Start with the index.html. It will point to sites explaining all
|
||||||
|
# keys and groups
|
||||||
|
html_slave = HTMLFormatter()
|
||||||
|
|
||||||
|
f = file('style.css', 'w')
|
||||||
|
print >> f, html_slave.createCSS()
|
||||||
|
|
||||||
|
f = file('index.html', 'w')
|
||||||
|
print >> f, html_slave.createIndex()
|
||||||
|
|
||||||
|
f = file('all_groups.html', 'w')
|
||||||
|
print >> f, html_slave.createGroupsSite(doc)
|
||||||
|
|
||||||
|
f = file('all_keys.html', 'w')
|
||||||
|
print >> f, html_slave.createKeysSite(doc)
|
||||||
|
|
||||||
|
# now for each group create the site
|
||||||
|
for group in doc.groups():
|
||||||
|
f = file('group%s.html' % group, 'w')
|
||||||
|
print >> f, html_slave.createGroupSite(group, doc.group_content(group))
|
||||||
|
|
||||||
|
# now for the keys
|
||||||
|
for key in doc.doc_keys():
|
||||||
|
f = file('key%s.html' % doc.doc_item(key).name(), 'w')
|
||||||
|
print >> f, html_slave.createKeySite(doc.doc_item(key))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,10 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
#
|
|
||||||
# Copyright BitBake Contributors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
"""git-make-shallow: make the current git repository shallow
|
"""git-make-shallow: make the current git repository shallow
|
||||||
|
|
||||||
Remove the history of the specified revisions, then optionally filter the
|
Remove the history of the specified revisions, then optionally filter the
|
||||||
@@ -18,23 +12,19 @@ import itertools
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
|
||||||
warnings.simplefilter("default")
|
|
||||||
|
|
||||||
version = 1.0
|
version = 1.0
|
||||||
|
|
||||||
|
|
||||||
git_cmd = ['git', '-c', 'safe.bareRepository=all']
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if sys.version_info < (3, 4, 0):
|
if sys.version_info < (3, 4, 0):
|
||||||
sys.exit('Python 3.4 or greater is required')
|
sys.exit('Python 3.4 or greater is required')
|
||||||
|
|
||||||
git_dir = check_output(git_cmd + ['rev-parse', '--git-dir']).rstrip()
|
git_dir = check_output(['git', 'rev-parse', '--git-dir']).rstrip()
|
||||||
shallow_file = os.path.join(git_dir, 'shallow')
|
shallow_file = os.path.join(git_dir, 'shallow')
|
||||||
if os.path.exists(shallow_file):
|
if os.path.exists(shallow_file):
|
||||||
try:
|
try:
|
||||||
check_output(git_cmd + ['fetch', '--unshallow'])
|
check_output(['git', 'fetch', '--unshallow'])
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
try:
|
try:
|
||||||
os.unlink(shallow_file)
|
os.unlink(shallow_file)
|
||||||
@@ -43,21 +33,21 @@ def main():
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
args = process_args()
|
args = process_args()
|
||||||
revs = check_output(git_cmd + ['rev-list'] + args.revisions).splitlines()
|
revs = check_output(['git', 'rev-list'] + args.revisions).splitlines()
|
||||||
|
|
||||||
make_shallow(shallow_file, args.revisions, args.refs)
|
make_shallow(shallow_file, args.revisions, args.refs)
|
||||||
|
|
||||||
ref_revs = check_output(git_cmd + ['rev-list'] + args.refs).splitlines()
|
ref_revs = check_output(['git', 'rev-list'] + args.refs).splitlines()
|
||||||
remaining_history = set(revs) & set(ref_revs)
|
remaining_history = set(revs) & set(ref_revs)
|
||||||
for rev in remaining_history:
|
for rev in remaining_history:
|
||||||
if check_output(git_cmd + ['rev-parse', '{}^@'.format(rev)]):
|
if check_output(['git', 'rev-parse', '{}^@'.format(rev)]):
|
||||||
sys.exit('Error: %s was not made shallow' % rev)
|
sys.exit('Error: %s was not made shallow' % rev)
|
||||||
|
|
||||||
filter_refs(args.refs)
|
filter_refs(args.refs)
|
||||||
|
|
||||||
if args.shrink:
|
if args.shrink:
|
||||||
shrink_repo(git_dir)
|
shrink_repo(git_dir)
|
||||||
subprocess.check_call(git_cmd + ['fsck', '--unreachable'])
|
subprocess.check_call(['git', 'fsck', '--unreachable'])
|
||||||
|
|
||||||
|
|
||||||
def process_args():
|
def process_args():
|
||||||
@@ -74,12 +64,12 @@ def process_args():
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.refs:
|
if args.refs:
|
||||||
args.refs = check_output(git_cmd + ['rev-parse', '--symbolic-full-name'] + args.refs).splitlines()
|
args.refs = check_output(['git', 'rev-parse', '--symbolic-full-name'] + args.refs).splitlines()
|
||||||
else:
|
else:
|
||||||
args.refs = get_all_refs(lambda r, t, tt: t == 'commit' or tt == 'commit')
|
args.refs = get_all_refs(lambda r, t, tt: t == 'commit' or tt == 'commit')
|
||||||
|
|
||||||
args.refs = list(filter(lambda r: not r.endswith('/HEAD'), args.refs))
|
args.refs = list(filter(lambda r: not r.endswith('/HEAD'), args.refs))
|
||||||
args.revisions = check_output(git_cmd + ['rev-parse'] + ['%s^{}' % i for i in args.revisions]).splitlines()
|
args.revisions = check_output(['git', 'rev-parse'] + ['%s^{}' % i for i in args.revisions]).splitlines()
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
@@ -97,7 +87,7 @@ def make_shallow(shallow_file, revisions, refs):
|
|||||||
|
|
||||||
def get_all_refs(ref_filter=None):
|
def get_all_refs(ref_filter=None):
|
||||||
"""Return all the existing refs in this repository, optionally filtering the refs."""
|
"""Return all the existing refs in this repository, optionally filtering the refs."""
|
||||||
ref_output = check_output(git_cmd + ['for-each-ref', '--format=%(refname)\t%(objecttype)\t%(*objecttype)'])
|
ref_output = check_output(['git', 'for-each-ref', '--format=%(refname)\t%(objecttype)\t%(*objecttype)'])
|
||||||
ref_split = [tuple(iter_extend(l.rsplit('\t'), 3)) for l in ref_output.splitlines()]
|
ref_split = [tuple(iter_extend(l.rsplit('\t'), 3)) for l in ref_output.splitlines()]
|
||||||
if ref_filter:
|
if ref_filter:
|
||||||
ref_split = (e for e in ref_split if ref_filter(*e))
|
ref_split = (e for e in ref_split if ref_filter(*e))
|
||||||
@@ -115,7 +105,7 @@ def filter_refs(refs):
|
|||||||
all_refs = get_all_refs()
|
all_refs = get_all_refs()
|
||||||
to_remove = set(all_refs) - set(refs)
|
to_remove = set(all_refs) - set(refs)
|
||||||
if to_remove:
|
if to_remove:
|
||||||
check_output(['xargs', '-0', '-n', '1'] + git_cmd + ['update-ref', '-d', '--no-deref'],
|
check_output(['xargs', '-0', '-n', '1', 'git', 'update-ref', '-d', '--no-deref'],
|
||||||
input=''.join(l + '\0' for l in to_remove))
|
input=''.join(l + '\0' for l in to_remove))
|
||||||
|
|
||||||
|
|
||||||
@@ -128,7 +118,7 @@ def follow_history_intersections(revisions, refs):
|
|||||||
if rev in seen:
|
if rev in seen:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
parents = check_output(git_cmd + ['rev-parse', '%s^@' % rev]).splitlines()
|
parents = check_output(['git', 'rev-parse', '%s^@' % rev]).splitlines()
|
||||||
|
|
||||||
yield rev
|
yield rev
|
||||||
seen.add(rev)
|
seen.add(rev)
|
||||||
@@ -136,12 +126,12 @@ def follow_history_intersections(revisions, refs):
|
|||||||
if not parents:
|
if not parents:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
check_refs = check_output(git_cmd + ['merge-base', '--independent'] + sorted(refs)).splitlines()
|
check_refs = check_output(['git', 'merge-base', '--independent'] + sorted(refs)).splitlines()
|
||||||
for parent in parents:
|
for parent in parents:
|
||||||
for ref in check_refs:
|
for ref in check_refs:
|
||||||
print("Checking %s vs %s" % (parent, ref))
|
print("Checking %s vs %s" % (parent, ref))
|
||||||
try:
|
try:
|
||||||
merge_base = check_output(git_cmd + ['merge-base', parent, ref]).rstrip()
|
merge_base = check_output(['git', 'merge-base', parent, ref]).rstrip()
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
@@ -161,14 +151,14 @@ def iter_except(func, exception, start=None):
|
|||||||
|
|
||||||
def shrink_repo(git_dir):
|
def shrink_repo(git_dir):
|
||||||
"""Shrink the newly shallow repository, removing the unreachable objects."""
|
"""Shrink the newly shallow repository, removing the unreachable objects."""
|
||||||
subprocess.check_call(git_cmd + ['reflog', 'expire', '--expire-unreachable=now', '--all'])
|
subprocess.check_call(['git', 'reflog', 'expire', '--expire-unreachable=now', '--all'])
|
||||||
subprocess.check_call(git_cmd + ['repack', '-ad'])
|
subprocess.check_call(['git', 'repack', '-ad'])
|
||||||
try:
|
try:
|
||||||
os.unlink(os.path.join(git_dir, 'objects', 'info', 'alternates'))
|
os.unlink(os.path.join(git_dir, 'objects', 'info', 'alternates'))
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
if exc.errno != errno.ENOENT:
|
if exc.errno != errno.ENOENT:
|
||||||
raise
|
raise
|
||||||
subprocess.check_call(git_cmd + ['prune', '--expire', 'now'])
|
subprocess.check_call(['git', 'prune', '--expire', 'now'])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -3,18 +3,27 @@
|
|||||||
# toaster - shell script to start Toaster
|
# toaster - shell script to start Toaster
|
||||||
|
|
||||||
# Copyright (C) 2013-2015 Intel Corp.
|
# Copyright (C) 2013-2015 Intel Corp.
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see http://www.gnu.org/licenses/.
|
||||||
|
|
||||||
HELP="
|
HELP="
|
||||||
Usage 1: source toaster start|stop [webport=<address:port>] [noweb] [nobuild] [toasterdir]
|
Usage: source toaster start|stop [webport=<address:port>] [noweb] [nobuild] [toasterdir]
|
||||||
Optional arguments:
|
Optional arguments:
|
||||||
[nobuild] Setup the environment for capturing builds with toaster but disable managed builds
|
[nobuild] Setup the environment for capturing builds with toaster but disable managed builds
|
||||||
[noweb] Setup the environment for capturing builds with toaster but don't start the web server
|
[noweb] Setup the environment for capturing builds with toaster but don't start the web server
|
||||||
[webport] Set the development server (default: localhost:8000)
|
[webport] Set the development server (default: localhost:8000)
|
||||||
[toasterdir] Set absolute path to be used as TOASTER_DIR (default: BUILDDIR/../)
|
[toasterdir] Set absolute path to be used as TOASTER_DIR (default: BUILDDIR/../)
|
||||||
Usage 2: source toaster manage [createsuperuser|lsupdates|migrate|makemigrations|checksettings|collectstatic|...]
|
|
||||||
"
|
"
|
||||||
|
|
||||||
custom_extention()
|
custom_extention()
|
||||||
@@ -33,7 +42,7 @@ databaseCheck()
|
|||||||
$MANAGE migrate --noinput || retval=1
|
$MANAGE migrate --noinput || retval=1
|
||||||
|
|
||||||
if [ $retval -eq 1 ]; then
|
if [ $retval -eq 1 ]; then
|
||||||
echo "Failed migrations, halting system start" 1>&2
|
echo "Failed migrations, aborting system start" 1>&2
|
||||||
return $retval
|
return $retval
|
||||||
fi
|
fi
|
||||||
# Make sure that checksettings can pick up any value for TEMPLATECONF
|
# Make sure that checksettings can pick up any value for TEMPLATECONF
|
||||||
@@ -41,7 +50,7 @@ databaseCheck()
|
|||||||
$MANAGE checksettings --traceback || retval=1
|
$MANAGE checksettings --traceback || retval=1
|
||||||
|
|
||||||
if [ $retval -eq 1 ]; then
|
if [ $retval -eq 1 ]; then
|
||||||
printf "\nError while checking settings; exiting\n"
|
printf "\nError while checking settings; aborting\n"
|
||||||
return $retval
|
return $retval
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -84,7 +93,7 @@ webserverStartAll()
|
|||||||
echo "Starting webserver..."
|
echo "Starting webserver..."
|
||||||
|
|
||||||
$MANAGE runserver --noreload "$ADDR_PORT" \
|
$MANAGE runserver --noreload "$ADDR_PORT" \
|
||||||
</dev/null >>${TOASTER_LOGS_DIR}/web.log 2>&1 \
|
</dev/null >>${BUILDDIR}/toaster_web.log 2>&1 \
|
||||||
& echo $! >${BUILDDIR}/.toastermain.pid
|
& echo $! >${BUILDDIR}/.toastermain.pid
|
||||||
|
|
||||||
sleep 1
|
sleep 1
|
||||||
@@ -181,14 +190,6 @@ WEBSERVER=1
|
|||||||
export TOASTER_BUILDSERVER=1
|
export TOASTER_BUILDSERVER=1
|
||||||
ADDR_PORT="localhost:8000"
|
ADDR_PORT="localhost:8000"
|
||||||
TOASTERDIR=`dirname $BUILDDIR`
|
TOASTERDIR=`dirname $BUILDDIR`
|
||||||
# ${BUILDDIR}/toaster_logs/ became the default location for toaster logs
|
|
||||||
# This is needed for implemented django-log-viewer: https://pypi.org/project/django-log-viewer/
|
|
||||||
# If the directory does not exist, create it.
|
|
||||||
TOASTER_LOGS_DIR="${BUILDDIR}/toaster_logs/"
|
|
||||||
if [ ! -d $TOASTER_LOGS_DIR ]
|
|
||||||
then
|
|
||||||
mkdir $TOASTER_LOGS_DIR
|
|
||||||
fi
|
|
||||||
unset CMD
|
unset CMD
|
||||||
for param in $*; do
|
for param in $*; do
|
||||||
case $param in
|
case $param in
|
||||||
@@ -217,21 +218,13 @@ for param in $*; do
|
|||||||
toasterdir=*)
|
toasterdir=*)
|
||||||
TOASTERDIR="${param#*=}"
|
TOASTERDIR="${param#*=}"
|
||||||
;;
|
;;
|
||||||
manage )
|
|
||||||
CMD=$param
|
|
||||||
manage_cmd=""
|
|
||||||
;;
|
|
||||||
--help)
|
--help)
|
||||||
echo "$HELP"
|
echo "$HELP"
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
if [ "manage" == "$CMD" ] ; then
|
echo "$HELP"
|
||||||
manage_cmd="$manage_cmd $param"
|
return 1
|
||||||
else
|
|
||||||
echo "$HELP"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
@@ -256,7 +249,7 @@ fi
|
|||||||
# 3) the sqlite db if that is being used.
|
# 3) the sqlite db if that is being used.
|
||||||
# 4) pid's we need to clean up on exit/shutdown
|
# 4) pid's we need to clean up on exit/shutdown
|
||||||
export TOASTER_DIR=$TOASTERDIR
|
export TOASTER_DIR=$TOASTERDIR
|
||||||
export BB_ENV_PASSTHROUGH_ADDITIONS="$BB_ENV_PASSTHROUGH_ADDITIONS TOASTER_DIR"
|
export BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE TOASTER_DIR"
|
||||||
|
|
||||||
# Determine the action. If specified by arguments, fine, if not, toggle it
|
# Determine the action. If specified by arguments, fine, if not, toggle it
|
||||||
if [ "$CMD" = "start" ] ; then
|
if [ "$CMD" = "start" ] ; then
|
||||||
@@ -307,7 +300,7 @@ case $CMD in
|
|||||||
export BITBAKE_UI='toasterui'
|
export BITBAKE_UI='toasterui'
|
||||||
if [ $TOASTER_BUILDSERVER -eq 1 ] ; then
|
if [ $TOASTER_BUILDSERVER -eq 1 ] ; then
|
||||||
$MANAGE runbuilds \
|
$MANAGE runbuilds \
|
||||||
</dev/null >>${TOASTER_LOGS_DIR}/toaster_runbuilds.log 2>&1 \
|
</dev/null >>${BUILDDIR}/toaster_runbuilds.log 2>&1 \
|
||||||
& echo $! >${BUILDDIR}/.runbuilds.pid
|
& echo $! >${BUILDDIR}/.runbuilds.pid
|
||||||
else
|
else
|
||||||
echo "Toaster build server not started."
|
echo "Toaster build server not started."
|
||||||
@@ -323,10 +316,6 @@ case $CMD in
|
|||||||
stop_system
|
stop_system
|
||||||
echo "Successful ${CMD}."
|
echo "Successful ${CMD}."
|
||||||
;;
|
;;
|
||||||
manage )
|
|
||||||
cd $BBBASEDIR/lib/toaster
|
|
||||||
$MANAGE $manage_cmd
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
custom_extention toaster_postpend $CMD $ADDR_PORT
|
custom_extention toaster_postpend $CMD $ADDR_PORT
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,25 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# ex:ts=4:sw=4:sts=4:et
|
||||||
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2014 Alex Damian
|
# Copyright (C) 2014 Alex Damian
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
# This file re-uses code spread throughout other Bitbake source files.
|
# This file re-uses code spread throughout other Bitbake source files.
|
||||||
# As such, all other copyrights belong to their own right holders.
|
# As such, all other copyrights belong to their own right holders.
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This command takes a filename as a single parameter. The filename is read
|
This command takes a filename as a single parameter. The filename is read
|
||||||
@@ -19,8 +32,6 @@ import sys
|
|||||||
import json
|
import json
|
||||||
import pickle
|
import pickle
|
||||||
import codecs
|
import codecs
|
||||||
import warnings
|
|
||||||
warnings.simplefilter("default")
|
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
@@ -30,23 +41,79 @@ sys.path.insert(0, join(dirname(dirname(abspath(__file__))), 'lib'))
|
|||||||
|
|
||||||
import bb.cooker
|
import bb.cooker
|
||||||
from bb.ui import toasterui
|
from bb.ui import toasterui
|
||||||
from bb.ui import eventreplay
|
|
||||||
|
class EventPlayer:
|
||||||
|
"""Emulate a connection to a bitbake server."""
|
||||||
|
|
||||||
|
def __init__(self, eventfile, variables):
|
||||||
|
self.eventfile = eventfile
|
||||||
|
self.variables = variables
|
||||||
|
self.eventmask = []
|
||||||
|
|
||||||
|
def waitEvent(self, _timeout):
|
||||||
|
"""Read event from the file."""
|
||||||
|
line = self.eventfile.readline().strip()
|
||||||
|
if not line:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
event_str = json.loads(line)['vars'].encode('utf-8')
|
||||||
|
event = pickle.loads(codecs.decode(event_str, 'base64'))
|
||||||
|
event_name = "%s.%s" % (event.__module__, event.__class__.__name__)
|
||||||
|
if event_name not in self.eventmask:
|
||||||
|
return
|
||||||
|
return event
|
||||||
|
except ValueError as err:
|
||||||
|
print("Failed loading ", line)
|
||||||
|
raise err
|
||||||
|
|
||||||
|
def runCommand(self, command_line):
|
||||||
|
"""Emulate running a command on the server."""
|
||||||
|
name = command_line[0]
|
||||||
|
|
||||||
|
if name == "getVariable":
|
||||||
|
var_name = command_line[1]
|
||||||
|
variable = self.variables.get(var_name)
|
||||||
|
if variable:
|
||||||
|
return variable['v'], None
|
||||||
|
return None, "Missing variable %s" % var_name
|
||||||
|
|
||||||
|
elif name == "getAllKeysWithFlags":
|
||||||
|
dump = {}
|
||||||
|
flaglist = command_line[1]
|
||||||
|
for key, val in self.variables.items():
|
||||||
|
try:
|
||||||
|
if not key.startswith("__"):
|
||||||
|
dump[key] = {
|
||||||
|
'v': val['v'],
|
||||||
|
'history' : val['history'],
|
||||||
|
}
|
||||||
|
for flag in flaglist:
|
||||||
|
dump[key][flag] = val[flag]
|
||||||
|
except Exception as err:
|
||||||
|
print(err)
|
||||||
|
return (dump, None)
|
||||||
|
|
||||||
|
elif name == 'setEventMask':
|
||||||
|
self.eventmask = command_line[-1]
|
||||||
|
return True, None
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise Exception("Command %s not implemented" % command_line[0])
|
||||||
|
|
||||||
|
def getEventHandle(self):
|
||||||
|
"""
|
||||||
|
This method is called by toasterui.
|
||||||
|
The return value is passed to self.runCommand but not used there.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
with open(argv[-1]) as eventfile:
|
with open(argv[-1]) as eventfile:
|
||||||
# load variables from the first line
|
# load variables from the first line
|
||||||
variables = None
|
variables = json.loads(eventfile.readline().strip())['allvariables']
|
||||||
while line := eventfile.readline().strip():
|
|
||||||
try:
|
|
||||||
variables = json.loads(line)['allvariables']
|
|
||||||
break
|
|
||||||
except (KeyError, json.JSONDecodeError):
|
|
||||||
continue
|
|
||||||
if not variables:
|
|
||||||
sys.exit("Cannot find allvariables entry in event log file %s" % argv[-1])
|
|
||||||
eventfile.seek(0)
|
|
||||||
params = namedtuple('ConfigParams', ['observe_only'])(True)
|
params = namedtuple('ConfigParams', ['observe_only'])(True)
|
||||||
player = eventreplay.EventPlayer(eventfile, variables)
|
player = EventPlayer(eventfile, variables)
|
||||||
|
|
||||||
return toasterui.main(player, player, params)
|
return toasterui.main(player, player, params)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"loggers": {
|
|
||||||
"BitBake.SigGen.HashEquiv": {
|
|
||||||
"level": "VERBOSE",
|
|
||||||
"handlers": ["BitBake.verbconsole"]
|
|
||||||
},
|
|
||||||
"BitBake.RunQueue.HashEquiv": {
|
|
||||||
"level": "VERBOSE",
|
|
||||||
"handlers": ["BitBake.verbconsole"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
#! /usr/bin/env python3
|
|
||||||
#
|
|
||||||
# Copyright (C) 2020 Joshua Watt <JPEWhacker@gmail.com>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
import shutil
|
|
||||||
import signal
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
def try_unlink(path):
|
|
||||||
try:
|
|
||||||
os.unlink(path)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
def cleanup():
|
|
||||||
shutil.rmtree("tmp/cache", ignore_errors=True)
|
|
||||||
try_unlink("bitbake-cookerdaemon.log")
|
|
||||||
try_unlink("bitbake.sock")
|
|
||||||
try_unlink("bitbake.lock")
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="Bitbake parser torture test",
|
|
||||||
epilog="""
|
|
||||||
A torture test for bitbake's parser. Repeatedly interrupts parsing until
|
|
||||||
bitbake decides to deadlock.
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if not "BUILDDIR" in os.environ:
|
|
||||||
print(
|
|
||||||
"'BUILDDIR' not found in the environment. Did you initialize the build environment?"
|
|
||||||
)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
os.chdir(os.environ["BUILDDIR"])
|
|
||||||
|
|
||||||
run_num = 0
|
|
||||||
while True:
|
|
||||||
if run_num % 100 == 0:
|
|
||||||
print("Calibrating wait time...")
|
|
||||||
cleanup()
|
|
||||||
|
|
||||||
start_time = time.monotonic()
|
|
||||||
r = subprocess.run(["bitbake", "-p"])
|
|
||||||
max_wait_time = time.monotonic() - start_time
|
|
||||||
|
|
||||||
if r.returncode != 0:
|
|
||||||
print("Calibration run exited with %d" % r.returncode)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
print("Maximum wait time is %f seconds" % max_wait_time)
|
|
||||||
|
|
||||||
run_num += 1
|
|
||||||
wait_time = random.random() * max_wait_time
|
|
||||||
|
|
||||||
print("Run #%d" % run_num)
|
|
||||||
print("Will sleep for %f seconds" % wait_time)
|
|
||||||
|
|
||||||
cleanup()
|
|
||||||
with subprocess.Popen(["bitbake", "-p"]) as proc:
|
|
||||||
time.sleep(wait_time)
|
|
||||||
proc.send_signal(signal.SIGINT)
|
|
||||||
try:
|
|
||||||
proc.wait(45)
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
print("Run #%d: Waited too long. Possible deadlock!" % run_num)
|
|
||||||
proc.wait()
|
|
||||||
return 1
|
|
||||||
|
|
||||||
if proc.returncode == 0:
|
|
||||||
print("Exited successfully. Timeout too long?")
|
|
||||||
else:
|
|
||||||
print("Exited with %d" % proc.returncode)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# ex:ts=4:sw=4:sts=4:et
|
||||||
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2012, 2018 Wind River Systems, Inc.
|
# Copyright (C) 2012, 2018 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
|
||||||
#
|
|
||||||
# Copyright (c) 2021 Joshua Watt <JPEWhacker@gmail.com>
|
|
||||||
#
|
|
||||||
# Dockerfile to build a bitbake hash equivalence server container
|
|
||||||
#
|
|
||||||
# From the root of the bitbake repository, run:
|
|
||||||
#
|
|
||||||
# docker build -f contrib/hashserv/Dockerfile .
|
|
||||||
#
|
|
||||||
|
|
||||||
FROM alpine:3.13.1
|
|
||||||
|
|
||||||
RUN apk add --no-cache python3
|
|
||||||
|
|
||||||
COPY bin/bitbake-hashserv /opt/bbhashserv/bin/
|
|
||||||
COPY lib/hashserv /opt/bbhashserv/lib/hashserv/
|
|
||||||
COPY lib/bb /opt/bbhashserv/lib/bb/
|
|
||||||
COPY lib/codegen.py /opt/bbhashserv/lib/codegen.py
|
|
||||||
COPY lib/ply /opt/bbhashserv/lib/ply/
|
|
||||||
COPY lib/bs4 /opt/bbhashserv/lib/bs4/
|
|
||||||
|
|
||||||
ENTRYPOINT ["/opt/bbhashserv/bin/bitbake-hashserv"]
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
|
||||||
#
|
|
||||||
# Copyright (c) 2022 Daniel Gomez <daniel@qtec.com>
|
|
||||||
#
|
|
||||||
# Dockerfile to build a bitbake PR service container
|
|
||||||
#
|
|
||||||
# From the root of the bitbake repository, run:
|
|
||||||
#
|
|
||||||
# docker build -f contrib/prserv/Dockerfile . -t prserv
|
|
||||||
#
|
|
||||||
# Running examples:
|
|
||||||
#
|
|
||||||
# 1. PR Service in RW mode, port 18585:
|
|
||||||
#
|
|
||||||
# docker run --detach --tty \
|
|
||||||
# --env PORT=18585 \
|
|
||||||
# --publish 18585:18585 \
|
|
||||||
# --volume $PWD:/var/lib/bbprserv \
|
|
||||||
# prserv
|
|
||||||
#
|
|
||||||
# 2. PR Service in RO mode, default port (8585) and custom LOGFILE:
|
|
||||||
#
|
|
||||||
# docker run --detach --tty \
|
|
||||||
# --env DBMODE="--read-only" \
|
|
||||||
# --env LOGFILE=/var/lib/bbprserv/prservro.log \
|
|
||||||
# --publish 8585:8585 \
|
|
||||||
# --volume $PWD:/var/lib/bbprserv \
|
|
||||||
# prserv
|
|
||||||
#
|
|
||||||
|
|
||||||
FROM alpine:3.14.4
|
|
||||||
|
|
||||||
RUN apk add --no-cache python3
|
|
||||||
|
|
||||||
COPY bin/bitbake-prserv /opt/bbprserv/bin/
|
|
||||||
COPY lib/prserv /opt/bbprserv/lib/prserv/
|
|
||||||
COPY lib/bb /opt/bbprserv/lib/bb/
|
|
||||||
COPY lib/codegen.py /opt/bbprserv/lib/codegen.py
|
|
||||||
COPY lib/ply /opt/bbprserv/lib/ply/
|
|
||||||
COPY lib/bs4 /opt/bbprserv/lib/bs4/
|
|
||||||
|
|
||||||
ENV PATH=$PATH:/opt/bbprserv/bin
|
|
||||||
|
|
||||||
RUN mkdir -p /var/lib/bbprserv
|
|
||||||
|
|
||||||
ENV DBFILE=/var/lib/bbprserv/prserv.sqlite3 \
|
|
||||||
LOGFILE=/var/lib/bbprserv/prserv.log \
|
|
||||||
LOGLEVEL=debug \
|
|
||||||
HOST=0.0.0.0 \
|
|
||||||
PORT=8585 \
|
|
||||||
DBMODE=""
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/bin/sh", "-c", \
|
|
||||||
"bitbake-prserv \
|
|
||||||
--file=$DBFILE \
|
|
||||||
--log=$LOGFILE \
|
|
||||||
--loglevel=$LOGLEVEL \
|
|
||||||
--start \
|
|
||||||
--host=$HOST \
|
|
||||||
--port=$PORT \
|
|
||||||
$DBMODE \
|
|
||||||
&& tail -f $LOGFILE"]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
@@ -6,12 +6,12 @@
|
|||||||
"
|
"
|
||||||
" This sets up the syntax highlighting for BitBake files, like .bb, .bbclass and .inc
|
" This sets up the syntax highlighting for BitBake files, like .bb, .bbclass and .inc
|
||||||
|
|
||||||
if &compatible || version < 600 || exists("b:loaded_bitbake_plugin")
|
if &compatible || version < 600
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" .bb, .bbappend and .bbclass
|
" .bb, .bbappend and .bbclass
|
||||||
au BufNewFile,BufRead *.{bb,bbappend,bbclass} set filetype=bitbake
|
au BufNewFile,BufRead *.{bb,bbappend,bbclass} set filetype=bitbake
|
||||||
|
|
||||||
" .inc
|
" .inc
|
||||||
au BufNewFile,BufRead *.inc set filetype=bitbake
|
au BufNewFile,BufRead *.inc set filetype=bitbake
|
||||||
|
|||||||
@@ -1,13 +1,2 @@
|
|||||||
" Only do this when not done yet for this buffer
|
set sts=4 sw=4 et
|
||||||
if exists("b:did_ftplugin")
|
set cms=#%s
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Don't load another plugin for this buffer
|
|
||||||
let b:did_ftplugin = 1
|
|
||||||
|
|
||||||
let b:undo_ftplugin = "setl cms< sts< sw< et< sua<"
|
|
||||||
|
|
||||||
setlocal commentstring=#\ %s
|
|
||||||
setlocal softtabstop=4 shiftwidth=4 expandtab
|
|
||||||
setlocal suffixesadd+=.bb,.bbclass
|
|
||||||
|
|||||||
@@ -1,343 +0,0 @@
|
|||||||
" Vim indent file
|
|
||||||
" Language: BitBake
|
|
||||||
" Copyright: Copyright (C) 2019 Agilent Technologies, Inc.
|
|
||||||
" Maintainer: Chris Laplante <chris.laplante@agilent.com>
|
|
||||||
" License: You may redistribute this under the same terms as Vim itself
|
|
||||||
|
|
||||||
|
|
||||||
if exists("b:did_indent")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
if exists("*BitbakeIndent")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
runtime! indent/sh.vim
|
|
||||||
unlet b:did_indent
|
|
||||||
|
|
||||||
setlocal indentexpr=BitbakeIndent(v:lnum)
|
|
||||||
setlocal autoindent nolisp
|
|
||||||
|
|
||||||
function s:is_bb_python_func_def(lnum)
|
|
||||||
let stack = synstack(a:lnum, 1)
|
|
||||||
if len(stack) == 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
let top = synIDattr(stack[0], "name")
|
|
||||||
echo top
|
|
||||||
|
|
||||||
return synIDattr(stack[0], "name") == "bbPyFuncDef"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"""" begin modified from indent/python.vim, upstream commit 7a9bd7c1e0ce1baf5a02daf36eeae3638aa315c7
|
|
||||||
"""" This copied code is licensed the same as Vim itself.
|
|
||||||
setlocal indentkeys+=<:>,=elif,=except
|
|
||||||
|
|
||||||
let s:keepcpo= &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
let s:maxoff = 50 " maximum number of lines to look backwards for ()
|
|
||||||
|
|
||||||
function! GetBBPythonIndent(lnum)
|
|
||||||
|
|
||||||
" If this line is explicitly joined: If the previous line was also joined,
|
|
||||||
" line it up with that one, otherwise add two 'shiftwidth'
|
|
||||||
if getline(a:lnum - 1) =~ '\\$'
|
|
||||||
if a:lnum > 1 && getline(a:lnum - 2) =~ '\\$'
|
|
||||||
return indent(a:lnum - 1)
|
|
||||||
endif
|
|
||||||
return indent(a:lnum - 1) + (exists("g:pyindent_continue") ? eval(g:pyindent_continue) : (shiftwidth() * 2))
|
|
||||||
endif
|
|
||||||
|
|
||||||
" If the start of the line is in a string don't change the indent.
|
|
||||||
if has('syntax_items')
|
|
||||||
\ && synIDattr(synID(a:lnum, 1, 1), "name") =~ "String$"
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Search backwards for the previous non-empty line.
|
|
||||||
let plnum = prevnonblank(v:lnum - 1)
|
|
||||||
|
|
||||||
if plnum == 0
|
|
||||||
" This is the first non-empty line, use zero indent.
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
call cursor(plnum, 1)
|
|
||||||
|
|
||||||
" Identing inside parentheses can be very slow, regardless of the searchpair()
|
|
||||||
" timeout, so let the user disable this feature if he doesn't need it
|
|
||||||
let disable_parentheses_indenting = get(g:, "pyindent_disable_parentheses_indenting", 0)
|
|
||||||
|
|
||||||
if disable_parentheses_indenting == 1
|
|
||||||
let plindent = indent(plnum)
|
|
||||||
let plnumstart = plnum
|
|
||||||
else
|
|
||||||
" searchpair() can be slow sometimes, limit the time to 150 msec or what is
|
|
||||||
" put in g:pyindent_searchpair_timeout
|
|
||||||
let searchpair_stopline = 0
|
|
||||||
let searchpair_timeout = get(g:, 'pyindent_searchpair_timeout', 150)
|
|
||||||
|
|
||||||
" If the previous line is inside parenthesis, use the indent of the starting
|
|
||||||
" line.
|
|
||||||
" Trick: use the non-existing "dummy" variable to break out of the loop when
|
|
||||||
" going too far back.
|
|
||||||
let parlnum = searchpair('(\|{\|\[', '', ')\|}\|\]', 'nbW',
|
|
||||||
\ "line('.') < " . (plnum - s:maxoff) . " ? dummy :"
|
|
||||||
\ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
|
|
||||||
\ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
|
|
||||||
\ searchpair_stopline, searchpair_timeout)
|
|
||||||
if parlnum > 0
|
|
||||||
" We may have found the opening brace of a BitBake Python task, e.g. 'python do_task {'
|
|
||||||
" If so, ignore it here - it will be handled later.
|
|
||||||
if s:is_bb_python_func_def(parlnum)
|
|
||||||
let parlnum = 0
|
|
||||||
let plindent = indent(plnum)
|
|
||||||
let plnumstart = plnum
|
|
||||||
else
|
|
||||||
let plindent = indent(parlnum)
|
|
||||||
let plnumstart = parlnum
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let plindent = indent(plnum)
|
|
||||||
let plnumstart = plnum
|
|
||||||
endif
|
|
||||||
|
|
||||||
" When inside parenthesis: If at the first line below the parenthesis add
|
|
||||||
" two 'shiftwidth', otherwise same as previous line.
|
|
||||||
" i = (a
|
|
||||||
" + b
|
|
||||||
" + c)
|
|
||||||
call cursor(a:lnum, 1)
|
|
||||||
let p = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW',
|
|
||||||
\ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
|
|
||||||
\ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
|
|
||||||
\ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
|
|
||||||
\ searchpair_stopline, searchpair_timeout)
|
|
||||||
if p > 0
|
|
||||||
if s:is_bb_python_func_def(p)
|
|
||||||
" Handle first non-empty line inside a BB Python task
|
|
||||||
if p == plnum
|
|
||||||
return shiftwidth()
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Handle the user actually trying to close a BitBake Python task
|
|
||||||
let line = getline(a:lnum)
|
|
||||||
if line =~ '^\s*}'
|
|
||||||
return -2
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Otherwise ignore the brace
|
|
||||||
let p = 0
|
|
||||||
else
|
|
||||||
if p == plnum
|
|
||||||
" When the start is inside parenthesis, only indent one 'shiftwidth'.
|
|
||||||
let pp = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW',
|
|
||||||
\ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
|
|
||||||
\ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
|
|
||||||
\ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
|
|
||||||
\ searchpair_stopline, searchpair_timeout)
|
|
||||||
if pp > 0
|
|
||||||
return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth())
|
|
||||||
endif
|
|
||||||
return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (shiftwidth() * 2))
|
|
||||||
endif
|
|
||||||
if plnumstart == p
|
|
||||||
return indent(plnum)
|
|
||||||
endif
|
|
||||||
return plindent
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
" Get the line and remove a trailing comment.
|
|
||||||
" Use syntax highlighting attributes when possible.
|
|
||||||
let pline = getline(plnum)
|
|
||||||
let pline_len = strlen(pline)
|
|
||||||
if has('syntax_items')
|
|
||||||
" If the last character in the line is a comment, do a binary search for
|
|
||||||
" the start of the comment. synID() is slow, a linear search would take
|
|
||||||
" too long on a long line.
|
|
||||||
if synIDattr(synID(plnum, pline_len, 1), "name") =~ "\\(Comment\\|Todo\\)$"
|
|
||||||
let min = 1
|
|
||||||
let max = pline_len
|
|
||||||
while min < max
|
|
||||||
let col = (min + max) / 2
|
|
||||||
if synIDattr(synID(plnum, col, 1), "name") =~ "\\(Comment\\|Todo\\)$"
|
|
||||||
let max = col
|
|
||||||
else
|
|
||||||
let min = col + 1
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
let pline = strpart(pline, 0, min - 1)
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let col = 0
|
|
||||||
while col < pline_len
|
|
||||||
if pline[col] == '#'
|
|
||||||
let pline = strpart(pline, 0, col)
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
let col = col + 1
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
|
|
||||||
" If the previous line ended with a colon, indent this line
|
|
||||||
if pline =~ ':\s*$'
|
|
||||||
return plindent + shiftwidth()
|
|
||||||
endif
|
|
||||||
|
|
||||||
" If the previous line was a stop-execution statement...
|
|
||||||
" TODO: utilize this logic to deindent when ending a bbPyDefRegion
|
|
||||||
if getline(plnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\|bb\.fatal\)\>'
|
|
||||||
" See if the user has already dedented
|
|
||||||
if indent(a:lnum) > indent(plnum) - shiftwidth()
|
|
||||||
" If not, recommend one dedent
|
|
||||||
return indent(plnum) - shiftwidth()
|
|
||||||
endif
|
|
||||||
" Otherwise, trust the user
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
" If the current line begins with a keyword that lines up with "try"
|
|
||||||
if getline(a:lnum) =~ '^\s*\(except\|finally\)\>'
|
|
||||||
let lnum = a:lnum - 1
|
|
||||||
while lnum >= 1
|
|
||||||
if getline(lnum) =~ '^\s*\(try\|except\)\>'
|
|
||||||
let ind = indent(lnum)
|
|
||||||
if ind >= indent(a:lnum)
|
|
||||||
return -1 " indent is already less than this
|
|
||||||
endif
|
|
||||||
return ind " line up with previous try or except
|
|
||||||
endif
|
|
||||||
let lnum = lnum - 1
|
|
||||||
endwhile
|
|
||||||
return -1 " no matching "try"!
|
|
||||||
endif
|
|
||||||
|
|
||||||
" If the current line begins with a header keyword, dedent
|
|
||||||
if getline(a:lnum) =~ '^\s*\(elif\|else\)\>'
|
|
||||||
|
|
||||||
" Unless the previous line was a one-liner
|
|
||||||
if getline(plnumstart) =~ '^\s*\(for\|if\|try\)\>'
|
|
||||||
return plindent
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Or the user has already dedented
|
|
||||||
if indent(a:lnum) <= plindent - shiftwidth()
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
return plindent - shiftwidth()
|
|
||||||
endif
|
|
||||||
|
|
||||||
" When after a () construct we probably want to go back to the start line.
|
|
||||||
" a = (b
|
|
||||||
" + c)
|
|
||||||
" here
|
|
||||||
if parlnum > 0
|
|
||||||
return plindent
|
|
||||||
endif
|
|
||||||
|
|
||||||
return -1
|
|
||||||
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:keepcpo
|
|
||||||
unlet s:keepcpo
|
|
||||||
|
|
||||||
""" end of stuff from indent/python.vim
|
|
||||||
|
|
||||||
|
|
||||||
let b:did_indent = 1
|
|
||||||
setlocal indentkeys+=0\"
|
|
||||||
|
|
||||||
|
|
||||||
function! BitbakeIndent(lnum)
|
|
||||||
if !has('syntax_items')
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
let stack = synstack(a:lnum, 1)
|
|
||||||
if len(stack) == 0
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
let name = synIDattr(stack[0], "name")
|
|
||||||
|
|
||||||
" TODO: support different styles of indentation for assignments. For now,
|
|
||||||
" we only support like this:
|
|
||||||
" VAR = " \
|
|
||||||
" value1 \
|
|
||||||
" value2 \
|
|
||||||
" "
|
|
||||||
"
|
|
||||||
" i.e. each value indented by shiftwidth(), with the final quote " completely unindented.
|
|
||||||
if name == "bbVarValue"
|
|
||||||
" Quote handling is tricky. kernel.bbclass has this line for instance:
|
|
||||||
" EXTRA_OEMAKE = " HOSTCC="${BUILD_CC} ${BUILD_CFLAGS} ${BUILD_LDFLAGS}" " HOSTCPP="${BUILD_CPP}""
|
|
||||||
" Instead of trying to handle crazy cases like that, just assume that a
|
|
||||||
" double-quote on a line by itself (following an assignment) means the
|
|
||||||
" user is closing the assignment, and de-dent.
|
|
||||||
if getline(a:lnum) =~ '^\s*"$'
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
let prevstack = synstack(a:lnum - 1, 1)
|
|
||||||
if len(prevstack) == 0
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
let prevname = synIDattr(prevstack[0], "name")
|
|
||||||
|
|
||||||
" Only indent if there was actually a continuation character on
|
|
||||||
" the previous line, to avoid misleading indentation.
|
|
||||||
let prevlinelastchar = synIDattr(synID(a:lnum - 1, col([a:lnum - 1, "$"]) - 1, 1), "name")
|
|
||||||
let prev_continued = prevlinelastchar == "bbContinue"
|
|
||||||
|
|
||||||
" Did the previous line introduce an assignment?
|
|
||||||
if index(["bbVarDef", "bbVarFlagDef"], prevname) != -1
|
|
||||||
if prev_continued
|
|
||||||
return shiftwidth()
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !prev_continued
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Autoindent can take it from here
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if index(["bbPyDefRegion", "bbPyFuncRegion"], name) != -1
|
|
||||||
let ret = GetBBPythonIndent(a:lnum)
|
|
||||||
" Should normally always be indented by at least one shiftwidth; but allow
|
|
||||||
" return of -1 (defer to autoindent) or -2 (force indent to 0)
|
|
||||||
if ret == 0
|
|
||||||
return shiftwidth()
|
|
||||||
elseif ret == -2
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
return ret
|
|
||||||
endif
|
|
||||||
|
|
||||||
" TODO: GetShIndent doesn't detect tasks prepended with 'fakeroot'
|
|
||||||
" Need to submit a patch upstream to Vim to provide an extension point.
|
|
||||||
" Unlike the Python indenter, the Sh indenter is way too large to copy and
|
|
||||||
" modify here.
|
|
||||||
if name == "bbShFuncRegion"
|
|
||||||
return GetShIndent()
|
|
||||||
endif
|
|
||||||
|
|
||||||
" TODO:
|
|
||||||
" + heuristics for de-denting out of a bbPyDefRegion? e.g. when the user
|
|
||||||
" types an obvious BB keyword like addhandler or addtask, or starts
|
|
||||||
" writing a shell task. Maybe too hard to implement...
|
|
||||||
|
|
||||||
return -1
|
|
||||||
endfunction
|
|
||||||
14
bitbake/contrib/vim/plugin/newbb.vim
Normal file → Executable file
14
bitbake/contrib/vim/plugin/newbb.vim
Normal file → Executable file
@@ -10,7 +10,7 @@
|
|||||||
"
|
"
|
||||||
" Will try to use git to find the user name and email
|
" Will try to use git to find the user name and email
|
||||||
|
|
||||||
if &compatible || v:version < 600 || exists("b:loaded_bitbake_plugin")
|
if &compatible || v:version < 600
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ endfun
|
|||||||
fun! <SID>GetUserEmail()
|
fun! <SID>GetUserEmail()
|
||||||
let l:user_email = system("git config --get user.email")
|
let l:user_email = system("git config --get user.email")
|
||||||
if v:shell_error
|
if v:shell_error
|
||||||
return "unknown@user.org"
|
return "unknow@user.org"
|
||||||
else
|
else
|
||||||
return substitute(l:user_email, "\n", "", "")
|
return substitute(l:user_email, "\n", "", "")
|
||||||
endfun
|
endfun
|
||||||
@@ -41,10 +41,6 @@ fun! BBHeader()
|
|||||||
endfun
|
endfun
|
||||||
|
|
||||||
fun! NewBBTemplate()
|
fun! NewBBTemplate()
|
||||||
if line2byte(line('$') + 1) != -1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:paste = &paste
|
let l:paste = &paste
|
||||||
set nopaste
|
set nopaste
|
||||||
|
|
||||||
@@ -52,7 +48,7 @@ fun! NewBBTemplate()
|
|||||||
call BBHeader()
|
call BBHeader()
|
||||||
|
|
||||||
" New the bb template
|
" New the bb template
|
||||||
put ='SUMMARY = \"\"'
|
put ='DESCRIPTION = \"\"'
|
||||||
put ='HOMEPAGE = \"\"'
|
put ='HOMEPAGE = \"\"'
|
||||||
put ='LICENSE = \"\"'
|
put ='LICENSE = \"\"'
|
||||||
put ='SECTION = \"\"'
|
put ='SECTION = \"\"'
|
||||||
@@ -62,7 +58,7 @@ fun! NewBBTemplate()
|
|||||||
|
|
||||||
" Go to the first place to edit
|
" Go to the first place to edit
|
||||||
0
|
0
|
||||||
/^SUMMARY =/
|
/^DESCRIPTION =/
|
||||||
exec "normal 2f\""
|
exec "normal 2f\""
|
||||||
|
|
||||||
if paste == 1
|
if paste == 1
|
||||||
@@ -80,7 +76,7 @@ if v:progname =~ "vimdiff"
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
augroup NewBB
|
augroup NewBB
|
||||||
au BufNewFile,BufReadPost *.bb
|
au BufNewFile *.bb
|
||||||
\ if g:bb_create_on_empty |
|
\ if g:bb_create_on_empty |
|
||||||
\ call NewBBTemplate() |
|
\ call NewBBTemplate() |
|
||||||
\ endif
|
\ endif
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
" Vim plugin file
|
|
||||||
" Purpose: Create a template for new bbappend file
|
|
||||||
" Author: Joshua Watt <JPEWhacker@gmail.com>
|
|
||||||
" Copyright: Copyright (C) 2017 Joshua Watt <JPEWhacker@gmail.com>
|
|
||||||
"
|
|
||||||
" This file is licensed under the MIT license, see COPYING.MIT in
|
|
||||||
" this source distribution for the terms.
|
|
||||||
"
|
|
||||||
|
|
||||||
if &compatible || v:version < 600 || exists("b:loaded_bitbake_plugin")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
fun! NewBBAppendTemplate()
|
|
||||||
if line2byte(line('$') + 1) != -1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:paste = &paste
|
|
||||||
set nopaste
|
|
||||||
|
|
||||||
" New bbappend template
|
|
||||||
0 put ='FILESEXTRAPATHS:prepend := \"${THISDIR}/${PN}:\"'
|
|
||||||
2
|
|
||||||
|
|
||||||
if paste == 1
|
|
||||||
set paste
|
|
||||||
endif
|
|
||||||
endfun
|
|
||||||
|
|
||||||
if !exists("g:bb_create_on_empty")
|
|
||||||
let g:bb_create_on_empty = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
" disable in case of vimdiff
|
|
||||||
if v:progname =~ "vimdiff"
|
|
||||||
let g:bb_create_on_empty = 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
augroup NewBBAppend
|
|
||||||
au BufNewFile,BufReadPost *.bbappend
|
|
||||||
\ if g:bb_create_on_empty |
|
|
||||||
\ call NewBBAppendTemplate() |
|
|
||||||
\ endif
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"
|
"
|
||||||
" It's an entirely new type, just has specific syntax in shell and python code
|
" It's an entirely new type, just has specific syntax in shell and python code
|
||||||
|
|
||||||
if &compatible || v:version < 600 || exists("b:loaded_bitbake_plugin")
|
if &compatible || v:version < 600
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
if exists("b:current_syntax")
|
if exists("b:current_syntax")
|
||||||
@@ -51,34 +51,31 @@ syn region bbString matchgroup=bbQuote start=+'+ skip=+\\$+ end=+'+
|
|||||||
syn match bbExport "^export" nextgroup=bbIdentifier skipwhite
|
syn match bbExport "^export" nextgroup=bbIdentifier skipwhite
|
||||||
syn keyword bbExportFlag export contained nextgroup=bbIdentifier skipwhite
|
syn keyword bbExportFlag export contained nextgroup=bbIdentifier skipwhite
|
||||||
syn match bbIdentifier "[a-zA-Z0-9\-_\.\/\+]\+" display contained
|
syn match bbIdentifier "[a-zA-Z0-9\-_\.\/\+]\+" display contained
|
||||||
syn match bbVarDeref "${[a-zA-Z0-9\-_:\.\/\+]\+}" contained
|
syn match bbVarDeref "${[a-zA-Z0-9\-_\.\/\+]\+}" contained
|
||||||
syn match bbVarEq "\(:=\|+=\|=+\|\.=\|=\.\|?=\|??=\|=\)" contained nextgroup=bbVarValue
|
syn match bbVarEq "\(:=\|+=\|=+\|\.=\|=\.\|?=\|??=\|=\)" contained nextgroup=bbVarValue
|
||||||
syn match bbVarDef "^\(export\s*\)\?\([a-zA-Z0-9\-_\.\/\+][${}a-zA-Z0-9\-_:\.\/\+]*\)\s*\(:=\|+=\|=+\|\.=\|=\.\|?=\|??=\|=\)\@=" contains=bbExportFlag,bbIdentifier,bbOverrideOperator,bbVarDeref nextgroup=bbVarEq
|
syn match bbVarDef "^\(export\s*\)\?\([a-zA-Z0-9\-_\.\/\+]\+\(_[${}a-zA-Z0-9\-_\.\/\+]\+\)\?\)\s*\(:=\|+=\|=+\|\.=\|=\.\|?=\|??=\|=\)\@=" contains=bbExportFlag,bbIdentifier,bbVarDeref nextgroup=bbVarEq
|
||||||
syn match bbVarValue ".*$" contained contains=bbString,bbVarDeref,bbVarPyValue
|
syn match bbVarValue ".*$" contained contains=bbString,bbVarDeref,bbVarPyValue
|
||||||
syn region bbVarPyValue start=+${@+ skip=+\\$+ end=+}+ contained contains=@python
|
syn region bbVarPyValue start=+${@+ skip=+\\$+ end=+}+ contained contains=@python
|
||||||
|
|
||||||
" Vars metadata flags
|
" Vars metadata flags
|
||||||
syn match bbVarFlagDef "^\([a-zA-Z0-9\-_\.]\+\)\(\[[a-zA-Z0-9\-_\.+]\+\]\)\@=" contains=bbIdentifier nextgroup=bbVarFlagFlag
|
syn match bbVarFlagDef "^\([a-zA-Z0-9\-_\.]\+\)\(\[[a-zA-Z0-9\-_\.]\+\]\)\@=" contains=bbIdentifier nextgroup=bbVarFlagFlag
|
||||||
syn region bbVarFlagFlag matchgroup=bbArrayBrackets start="\[" end="\]\s*\(:=\|=\|.=\|=.|+=\|=+\|?=\)\@=" contained contains=bbIdentifier nextgroup=bbVarEq
|
syn region bbVarFlagFlag matchgroup=bbArrayBrackets start="\[" end="\]\s*\(=\|+=\|=+\|?=\)\@=" contained contains=bbIdentifier nextgroup=bbVarEq
|
||||||
|
|
||||||
" Includes and requires
|
" Includes and requires
|
||||||
syn keyword bbInclude inherit include require contained
|
syn keyword bbInclude inherit include require contained
|
||||||
syn match bbIncludeRest ".*$" contained contains=bbString,bbVarDeref,bbVarPyValue
|
syn match bbIncludeRest ".*$" contained contains=bbString,bbVarDeref
|
||||||
syn match bbIncludeLine "^\(inherit\|include\|require\)\s\+" contains=bbInclude nextgroup=bbIncludeRest
|
syn match bbIncludeLine "^\(inherit\|include\|require\)\s\+" contains=bbInclude nextgroup=bbIncludeRest
|
||||||
|
|
||||||
" Add taks and similar
|
" Add taks and similar
|
||||||
syn keyword bbStatement addtask deltask addhandler after before EXPORT_FUNCTIONS contained
|
syn keyword bbStatement addtask addhandler after before EXPORT_FUNCTIONS contained
|
||||||
syn match bbStatementRest /[^\\]*$/ skipwhite contained contains=bbStatement,bbVarDeref,bbVarPyValue
|
syn match bbStatementRest ".*$" skipwhite contained contains=bbStatement
|
||||||
syn region bbStatementRestCont start=/.*\\$/ end=/^[^\\]*$/ contained contains=bbStatement,bbVarDeref,bbVarPyValue,bbContinue keepend
|
syn match bbStatementLine "^\(addtask\|addhandler\|after\|before\|EXPORT_FUNCTIONS\)\s\+" contains=bbStatement nextgroup=bbStatementRest
|
||||||
syn match bbStatementLine "^\(addtask\|deltask\|addhandler\|after\|before\|EXPORT_FUNCTIONS\)\s\+" contains=bbStatement nextgroup=bbStatementRest,bbStatementRestCont
|
|
||||||
|
|
||||||
" OE Important Functions
|
" OE Important Functions
|
||||||
syn keyword bbOEFunctions do_fetch do_unpack do_patch do_configure do_compile do_stage do_install do_package contained
|
syn keyword bbOEFunctions do_fetch do_unpack do_patch do_configure do_compile do_stage do_install do_package contained
|
||||||
|
|
||||||
" Generic Functions
|
" Generic Functions
|
||||||
syn match bbFunction "\h[0-9A-Za-z_\-\.]*" display contained contains=bbOEFunctions
|
syn match bbFunction "\h[0-9A-Za-z_-]*" display contained contains=bbOEFunctions
|
||||||
|
|
||||||
syn keyword bbOverrideOperator append prepend remove contained
|
|
||||||
|
|
||||||
" BitBake shell metadata
|
" BitBake shell metadata
|
||||||
syn include @shell syntax/sh.vim
|
syn include @shell syntax/sh.vim
|
||||||
@@ -86,7 +83,7 @@ if exists("b:current_syntax")
|
|||||||
unlet b:current_syntax
|
unlet b:current_syntax
|
||||||
endif
|
endif
|
||||||
syn keyword bbShFakeRootFlag fakeroot contained
|
syn keyword bbShFakeRootFlag fakeroot contained
|
||||||
syn match bbShFuncDef "^\(fakeroot\s*\)\?\([\.0-9A-Za-z_:${}\-\.]\+\)\(python\)\@<!\(\s*()\s*\)\({\)\@=" contains=bbShFakeRootFlag,bbFunction,bbOverrideOperator,bbVarDeref,bbDelimiter nextgroup=bbShFuncRegion skipwhite
|
syn match bbShFuncDef "^\(fakeroot\s*\)\?\([0-9A-Za-z_${}-]\+\)\(python\)\@<!\(\s*()\s*\)\({\)\@=" contains=bbShFakeRootFlag,bbFunction,bbVarDeref,bbDelimiter nextgroup=bbShFuncRegion skipwhite
|
||||||
syn region bbShFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" contained contains=@shell
|
syn region bbShFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" contained contains=@shell
|
||||||
|
|
||||||
" Python value inside shell functions
|
" Python value inside shell functions
|
||||||
@@ -94,7 +91,7 @@ syn region shDeref start=+${@+ skip=+\\$+ excludenl end=+}+ contained co
|
|||||||
|
|
||||||
" BitBake python metadata
|
" BitBake python metadata
|
||||||
syn keyword bbPyFlag python contained
|
syn keyword bbPyFlag python contained
|
||||||
syn match bbPyFuncDef "^\(fakeroot\s*\)\?\(python\)\(\s\+[0-9A-Za-z_:${}\-\.]\+\)\?\(\s*()\s*\)\({\)\@=" contains=bbShFakeRootFlag,bbPyFlag,bbFunction,bbOverrideOperator,bbVarDeref,bbDelimiter nextgroup=bbPyFuncRegion skipwhite
|
syn match bbPyFuncDef "^\(python\s\+\)\([0-9A-Za-z_${}-]\+\)\?\(\s*()\s*\)\({\)\@=" contains=bbPyFlag,bbFunction,bbVarDeref,bbDelimiter nextgroup=bbPyFuncRegion skipwhite
|
||||||
syn region bbPyFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" contained contains=@python
|
syn region bbPyFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" contained contains=@python
|
||||||
|
|
||||||
" BitBake 'def'd python functions
|
" BitBake 'def'd python functions
|
||||||
@@ -123,9 +120,7 @@ hi def link bbPyFlag Type
|
|||||||
hi def link bbPyDef Statement
|
hi def link bbPyDef Statement
|
||||||
hi def link bbStatement Statement
|
hi def link bbStatement Statement
|
||||||
hi def link bbStatementRest Identifier
|
hi def link bbStatementRest Identifier
|
||||||
hi def link bbStatementRestCont Identifier
|
|
||||||
hi def link bbOEFunctions Special
|
hi def link bbOEFunctions Special
|
||||||
hi def link bbVarPyValue PreProc
|
hi def link bbVarPyValue PreProc
|
||||||
hi def link bbOverrideOperator Operator
|
|
||||||
|
|
||||||
let b:current_syntax = "bb"
|
let b:current_syntax = "bb"
|
||||||
|
|||||||
1
bitbake/doc/.gitignore
vendored
1
bitbake/doc/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
_build/
|
|
||||||
@@ -1,35 +1,91 @@
|
|||||||
# Minimal makefile for Sphinx documentation
|
# This is a single Makefile to handle all generated BitBake documents.
|
||||||
|
# The Makefile needs to live in the documentation directory and all figures used
|
||||||
|
# in any manuals must be .PNG files and live in the individual book's figures
|
||||||
|
# directory.
|
||||||
|
#
|
||||||
|
# The Makefile has these targets:
|
||||||
|
#
|
||||||
|
# pdf: generates a PDF version of a manual.
|
||||||
|
# html: generates an HTML version of a manual.
|
||||||
|
# tarball: creates a tarball for the doc files.
|
||||||
|
# validate: validates
|
||||||
|
# clean: removes files
|
||||||
|
#
|
||||||
|
# The Makefile generates an HTML version of every document. The
|
||||||
|
# variable DOC indicates the folder name for a given manual.
|
||||||
|
#
|
||||||
|
# To build a manual, you must invoke 'make' with the DOC argument.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# make DOC=bitbake-user-manual
|
||||||
|
# make pdf DOC=bitbake-user-manual
|
||||||
|
#
|
||||||
|
# The first example generates the HTML version of the User Manual.
|
||||||
|
# The second example generates the PDF version of the User Manual.
|
||||||
#
|
#
|
||||||
|
|
||||||
# You can set these variables from the command line, and also
|
ifeq ($(DOC),bitbake-user-manual)
|
||||||
# from the environment for the first two.
|
XSLTOPTS = --stringparam html.stylesheet bitbake-user-manual-style.css \
|
||||||
SPHINXOPTS ?= -W --keep-going -j auto
|
--stringparam chapter.autolabel 1 \
|
||||||
SPHINXBUILD ?= sphinx-build
|
--stringparam section.autolabel 1 \
|
||||||
SOURCEDIR = .
|
--stringparam section.label.includes.component.label 1 \
|
||||||
BUILDDIR = _build
|
--xinclude
|
||||||
DESTDIR = final
|
ALLPREQ = html tarball
|
||||||
|
TARFILES = bitbake-user-manual-style.css bitbake-user-manual.html figures/bitbake-title.png
|
||||||
|
MANUALS = $(DOC)/$(DOC).html
|
||||||
|
FIGURES = figures
|
||||||
|
STYLESHEET = $(DOC)/*.css
|
||||||
|
|
||||||
ifeq ($(shell if which $(SPHINXBUILD) >/dev/null 2>&1; then echo 1; else echo 0; fi),0)
|
|
||||||
$(error "The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed")
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Put it first so that "make" without argument is like "make help".
|
##
|
||||||
help:
|
# These URI should be rewritten by your distribution's xml catalog to
|
||||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
# match your localy installed XSL stylesheets.
|
||||||
|
XSL_BASE_URI = http://docbook.sourceforge.net/release/xsl/current
|
||||||
|
XSL_XHTML_URI = $(XSL_BASE_URI)/xhtml/docbook.xsl
|
||||||
|
|
||||||
.PHONY: help Makefile clean publish
|
all: $(ALLPREQ)
|
||||||
|
|
||||||
publish: Makefile html singlehtml
|
pdf:
|
||||||
rm -rf $(BUILDDIR)/$(DESTDIR)/
|
ifeq ($(DOC),bitbake-user-manual)
|
||||||
mkdir -p $(BUILDDIR)/$(DESTDIR)/
|
@echo " "
|
||||||
cp -r $(BUILDDIR)/html/* $(BUILDDIR)/$(DESTDIR)/
|
@echo "********** Building."$(DOC)
|
||||||
cp $(BUILDDIR)/singlehtml/index.html $(BUILDDIR)/$(DESTDIR)/singleindex.html
|
@echo " "
|
||||||
sed -i -e 's@index.html#@singleindex.html#@g' $(BUILDDIR)/$(DESTDIR)/singleindex.html
|
cd $(DOC); ../tools/docbook-to-pdf $(DOC).xml ../template; cd ..
|
||||||
|
endif
|
||||||
|
|
||||||
|
html:
|
||||||
|
ifeq ($(DOC),bitbake-user-manual)
|
||||||
|
# See http://www.sagehill.net/docbookxsl/HtmlOutput.html
|
||||||
|
@echo " "
|
||||||
|
@echo "******** Building "$(DOC)
|
||||||
|
@echo " "
|
||||||
|
cd $(DOC); xsltproc $(XSLTOPTS) -o $(DOC).html $(DOC)-customization.xsl $(DOC).xml; cd ..
|
||||||
|
endif
|
||||||
|
|
||||||
|
tarball: html
|
||||||
|
@echo " "
|
||||||
|
@echo "******** Creating Tarball of document files"
|
||||||
|
@echo " "
|
||||||
|
cd $(DOC); tar -cvzf $(DOC).tgz $(TARFILES); cd ..
|
||||||
|
|
||||||
|
validate:
|
||||||
|
cd $(DOC); xmllint --postvalid --xinclude --noout $(DOC).xml; cd ..
|
||||||
|
|
||||||
|
publish:
|
||||||
|
@if test -f $(DOC)/$(DOC).html; \
|
||||||
|
then \
|
||||||
|
echo " "; \
|
||||||
|
echo "******** Publishing "$(DOC)".html"; \
|
||||||
|
echo " "; \
|
||||||
|
scp -r $(MANUALS) $(STYLESHEET) docs.yp:/var/www/www.yoctoproject.org-docs/$(VER)/$(DOC); \
|
||||||
|
cd $(DOC); scp -r $(FIGURES) docs.yp:/var/www/www.yoctoproject.org-docs/$(VER)/$(DOC); \
|
||||||
|
else \
|
||||||
|
echo " "; \
|
||||||
|
echo $(DOC)".html missing. Generate the file first then try again."; \
|
||||||
|
echo " "; \
|
||||||
|
fi
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(BUILDDIR)
|
rm -rf $(MANUALS); rm $(DOC)/$(DOC).tgz;
|
||||||
|
|
||||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
||||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
||||||
%: Makefile
|
|
||||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
||||||
|
|||||||
@@ -8,48 +8,32 @@ Manual Organization
|
|||||||
|
|
||||||
Folders exist for individual manuals as follows:
|
Folders exist for individual manuals as follows:
|
||||||
|
|
||||||
* bitbake-user-manual --- The BitBake User Manual
|
* bitbake-user-manual - The BitBake User Manual
|
||||||
|
|
||||||
Each folder is self-contained regarding content and figures.
|
Each folder is self-contained regarding content and figures.
|
||||||
|
|
||||||
If you want to find HTML versions of the BitBake manuals on the web,
|
If you want to find HTML versions of the BitBake manuals on the web,
|
||||||
go to https://www.openembedded.org/wiki/Documentation.
|
go to http://www.openembedded.org/wiki/Documentation.
|
||||||
|
|
||||||
Sphinx
|
Makefile
|
||||||
======
|
========
|
||||||
|
|
||||||
The BitBake documentation was migrated from the original DocBook
|
The Makefile processes manual directories to create HTML, PDF,
|
||||||
format to Sphinx based documentation for the Yocto Project 3.2
|
tarballs, etc. Details on how the Makefile work are documented
|
||||||
release.
|
inside the Makefile. See that file for more information.
|
||||||
|
|
||||||
Additional information related to the Sphinx migration, and guidelines
|
To build a manual, you run the make command and pass it the name
|
||||||
for developers willing to contribute to the BitBake documentation can
|
of the folder containing the manual's contents.
|
||||||
be found in the Yocto Project Documentation README file:
|
For example, the following command run from the documentation directory
|
||||||
|
creates an HTML and a PDF version of the BitBake User Manual.
|
||||||
|
The DOC variable specifies the manual you are making:
|
||||||
|
|
||||||
https://git.yoctoproject.org/cgit/cgit.cgi/yocto-docs/tree/documentation/README
|
$ make DOC=bitbake-user-manual
|
||||||
|
|
||||||
How to build the Yocto Project documentation
|
template
|
||||||
============================================
|
========
|
||||||
|
Contains various templates, fonts, and some old PNG files.
|
||||||
|
|
||||||
Sphinx is written in Python. While it might work with Python2, for
|
tools
|
||||||
obvious reasons, we will only support building the BitBake
|
=====
|
||||||
documentation with Python3.
|
Contains a tool to convert the DocBook files to PDF format.
|
||||||
|
|
||||||
Sphinx might be available in your Linux distro packages repositories,
|
|
||||||
however it is not recommend using distro packages, as they might be
|
|
||||||
old versions, especially if you are using an LTS version of your
|
|
||||||
distro. The recommended method to install Sphinx and all required
|
|
||||||
dependencies is to use the Python Package Index (pip).
|
|
||||||
|
|
||||||
To install all required packages run:
|
|
||||||
|
|
||||||
$ pip3 install sphinx sphinx_rtd_theme pyyaml
|
|
||||||
|
|
||||||
To build the documentation locally, run:
|
|
||||||
|
|
||||||
$ cd doc
|
|
||||||
$ make html
|
|
||||||
|
|
||||||
The resulting HTML index page will be _build/html/index.html, and you
|
|
||||||
can browse your own copy of the locally generated documentation with
|
|
||||||
your browser.
|
|
||||||
|
|||||||
14
bitbake/doc/_templates/breadcrumbs.html
vendored
14
bitbake/doc/_templates/breadcrumbs.html
vendored
@@ -1,14 +0,0 @@
|
|||||||
{% extends "!breadcrumbs.html" %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}
|
|
||||||
<li>
|
|
||||||
<span class="doctype_switcher_placeholder">{{ doctype or 'single' }}</span>
|
|
||||||
<span class="version_switcher_placeholder">{{ release }}</span>
|
|
||||||
</li>
|
|
||||||
<li> »</li>
|
|
||||||
{% for doc in parents %}
|
|
||||||
<li><a href="{{ doc.link|e }}">{{ doc.title }}</a> »</li>
|
|
||||||
{% endfor %}
|
|
||||||
<li>{{ title }}</li>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
9
bitbake/doc/_templates/footer.html
vendored
9
bitbake/doc/_templates/footer.html
vendored
@@ -1,9 +0,0 @@
|
|||||||
<footer>
|
|
||||||
<hr/>
|
|
||||||
<div role="contentinfo">
|
|
||||||
<p>© Copyright {{ copyright }}
|
|
||||||
<br>Last updated on {{ last_updated }} from the <a href="https://git.openembedded.org/bitbake/">bitbake</a> git repository.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
7
bitbake/doc/_templates/layout.html
vendored
7
bitbake/doc/_templates/layout.html
vendored
@@ -1,7 +0,0 @@
|
|||||||
{% extends "!layout.html" %}
|
|
||||||
|
|
||||||
{% block extrabody %}
|
|
||||||
<div id="outdated-warning" style="text-align: center; background-color: #FFBABA; color: #6A0E0E;">
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version='1.0'?>
|
||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
|
||||||
|
|
||||||
|
<xsl:import href="http://downloads.yoctoproject.org/mirror/docbook-mirror/docbook-xsl-1.76.1/xhtml/docbook.xsl" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
<xsl:import href="../template/1.76.1/docbook-xsl-1.76.1/xhtml/docbook.xsl" />
|
||||||
|
|
||||||
|
<xsl:import href="http://docbook.sourceforge.net/release/xsl/1.76.1/xhtml/docbook.xsl" />
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:include href="../template/permalinks.xsl"/>
|
||||||
|
<xsl:include href="../template/section.title.xsl"/>
|
||||||
|
<xsl:include href="../template/component.title.xsl"/>
|
||||||
|
<xsl:include href="../template/division.title.xsl"/>
|
||||||
|
<xsl:include href="../template/formal.object.heading.xsl"/>
|
||||||
|
<xsl:include href="../template/gloss-permalinks.xsl"/>
|
||||||
|
|
||||||
|
<xsl:param name="html.stylesheet" select="'user-manual-style.css'" />
|
||||||
|
<xsl:param name="chapter.autolabel" select="1" />
|
||||||
|
<xsl:param name="section.autolabel" select="1" />
|
||||||
|
<xsl:param name="section.label.includes.component.label" select="1" />
|
||||||
|
<xsl:param name="appendix.autolabel">A</xsl:param>
|
||||||
|
|
||||||
|
<!-- <xsl:param name="generate.toc" select="'article nop'"></xsl:param> -->
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
@@ -1,761 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: CC-BY-2.5
|
|
||||||
|
|
||||||
=========
|
|
||||||
Execution
|
|
||||||
=========
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
The primary purpose for running BitBake is to produce some kind of
|
|
||||||
output such as a single installable package, a kernel, a software
|
|
||||||
development kit, or even a full, board-specific bootable Linux image,
|
|
||||||
complete with bootloader, kernel, and root filesystem. Of course, you
|
|
||||||
can execute the ``bitbake`` command with options that cause it to
|
|
||||||
execute single tasks, compile single recipe files, capture or clear
|
|
||||||
data, or simply return information about the execution environment.
|
|
||||||
|
|
||||||
This chapter describes BitBake's execution process from start to finish
|
|
||||||
when you use it to create an image. The execution process is launched
|
|
||||||
using the following command form::
|
|
||||||
|
|
||||||
$ bitbake target
|
|
||||||
|
|
||||||
For information on
|
|
||||||
the BitBake command and its options, see ":ref:`The BitBake Command
|
|
||||||
<bitbake-user-manual-command>`" section.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Prior to executing BitBake, you should take advantage of available
|
|
||||||
parallel thread execution on your build host by setting the
|
|
||||||
:term:`BB_NUMBER_THREADS` variable in
|
|
||||||
your project's ``local.conf`` configuration file.
|
|
||||||
|
|
||||||
A common method to determine this value for your build host is to run
|
|
||||||
the following::
|
|
||||||
|
|
||||||
$ grep processor /proc/cpuinfo
|
|
||||||
|
|
||||||
This command returns
|
|
||||||
the number of processors, which takes into account hyper-threading.
|
|
||||||
Thus, a quad-core build host with hyper-threading most likely shows
|
|
||||||
eight processors, which is the value you would then assign to
|
|
||||||
:term:`BB_NUMBER_THREADS`.
|
|
||||||
|
|
||||||
A possibly simpler solution is that some Linux distributions (e.g.
|
|
||||||
Debian and Ubuntu) provide the ``ncpus`` command.
|
|
||||||
|
|
||||||
Parsing the Base Configuration Metadata
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
The first thing BitBake does is parse base configuration metadata. Base
|
|
||||||
configuration metadata consists of your project's ``bblayers.conf`` file
|
|
||||||
to determine what layers BitBake needs to recognize, all necessary
|
|
||||||
``layer.conf`` files (one from each layer), and ``bitbake.conf``. The
|
|
||||||
data itself is of various types:
|
|
||||||
|
|
||||||
- **Recipes:** Details about particular pieces of software.
|
|
||||||
|
|
||||||
- **Class Data:** An abstraction of common build information (e.g. how to
|
|
||||||
build a Linux kernel).
|
|
||||||
|
|
||||||
- **Configuration Data:** Machine-specific settings, policy decisions,
|
|
||||||
and so forth. Configuration data acts as the glue to bind everything
|
|
||||||
together.
|
|
||||||
|
|
||||||
The ``layer.conf`` files are used to construct key variables such as
|
|
||||||
:term:`BBPATH` and :term:`BBFILES`.
|
|
||||||
:term:`BBPATH` is used to search for configuration and class files under the
|
|
||||||
``conf`` and ``classes`` directories, respectively. :term:`BBFILES` is used
|
|
||||||
to locate both recipe and recipe append files (``.bb`` and
|
|
||||||
``.bbappend``). If there is no ``bblayers.conf`` file, it is assumed the
|
|
||||||
user has set the :term:`BBPATH` and :term:`BBFILES` directly in the environment.
|
|
||||||
|
|
||||||
Next, the ``bitbake.conf`` file is located using the :term:`BBPATH` variable
|
|
||||||
that was just constructed. The ``bitbake.conf`` file may also include
|
|
||||||
other configuration files using the ``include`` or ``require``
|
|
||||||
directives.
|
|
||||||
|
|
||||||
Prior to parsing configuration files, BitBake looks at certain
|
|
||||||
variables, including:
|
|
||||||
|
|
||||||
- :term:`BB_ENV_PASSTHROUGH`
|
|
||||||
- :term:`BB_ENV_PASSTHROUGH_ADDITIONS`
|
|
||||||
- :term:`BB_PRESERVE_ENV`
|
|
||||||
- :term:`BB_ORIGENV`
|
|
||||||
- :term:`BITBAKE_UI`
|
|
||||||
|
|
||||||
The first four variables in this list relate to how BitBake treats shell
|
|
||||||
environment variables during task execution. By default, BitBake cleans
|
|
||||||
the environment variables and provides tight control over the shell
|
|
||||||
execution environment. However, through the use of these first four
|
|
||||||
variables, you can apply your control regarding the environment
|
|
||||||
variables allowed to be used by BitBake in the shell during execution of
|
|
||||||
tasks. See the
|
|
||||||
":ref:`bitbake-user-manual/bitbake-user-manual-metadata:Passing Information Into the Build Task Environment`"
|
|
||||||
section and the information about these variables in the variable
|
|
||||||
glossary for more information on how they work and on how to use them.
|
|
||||||
|
|
||||||
The base configuration metadata is global and therefore affects all
|
|
||||||
recipes and tasks that are executed.
|
|
||||||
|
|
||||||
BitBake first searches the current working directory for an optional
|
|
||||||
``conf/bblayers.conf`` configuration file. This file is expected to
|
|
||||||
contain a :term:`BBLAYERS` variable that is a
|
|
||||||
space-delimited list of 'layer' directories. Recall that if BitBake
|
|
||||||
cannot find a ``bblayers.conf`` file, then it is assumed the user has
|
|
||||||
set the :term:`BBPATH` and :term:`BBFILES` variables directly in the
|
|
||||||
environment.
|
|
||||||
|
|
||||||
For each directory (layer) in this list, a ``conf/layer.conf`` file is
|
|
||||||
located and parsed with the :term:`LAYERDIR` variable
|
|
||||||
being set to the directory where the layer was found. The idea is these
|
|
||||||
files automatically set up :term:`BBPATH` and other
|
|
||||||
variables correctly for a given build directory.
|
|
||||||
|
|
||||||
BitBake then expects to find the ``conf/bitbake.conf`` file somewhere in
|
|
||||||
the user-specified :term:`BBPATH`. That configuration file generally has
|
|
||||||
include directives to pull in any other metadata such as files specific
|
|
||||||
to the architecture, the machine, the local environment, and so forth.
|
|
||||||
|
|
||||||
Only variable definitions and include directives are allowed in BitBake
|
|
||||||
``.conf`` files. Some variables directly influence BitBake's behavior.
|
|
||||||
These variables might have been set from the environment depending on
|
|
||||||
the environment variables previously mentioned or set in the
|
|
||||||
configuration files. The ":ref:`bitbake-user-manual/bitbake-user-manual-ref-variables:Variables Glossary`"
|
|
||||||
chapter presents a full list of
|
|
||||||
variables.
|
|
||||||
|
|
||||||
After parsing configuration files, BitBake uses its rudimentary
|
|
||||||
inheritance mechanism, which is through class files, to inherit some
|
|
||||||
standard classes. BitBake parses a class when the inherit directive
|
|
||||||
responsible for getting that class is encountered.
|
|
||||||
|
|
||||||
The ``base.bbclass`` file is always included. Other classes that are
|
|
||||||
specified in the configuration using the
|
|
||||||
:term:`INHERIT` variable are also included. BitBake
|
|
||||||
searches for class files in a ``classes`` subdirectory under the paths
|
|
||||||
in :term:`BBPATH` in the same way as configuration files.
|
|
||||||
|
|
||||||
A good way to get an idea of the configuration files and the class files
|
|
||||||
used in your execution environment is to run the following BitBake
|
|
||||||
command::
|
|
||||||
|
|
||||||
$ bitbake -e > mybb.log
|
|
||||||
|
|
||||||
Examining the top of the ``mybb.log``
|
|
||||||
shows you the many configuration files and class files used in your
|
|
||||||
execution environment.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
You need to be aware of how BitBake parses curly braces. If a recipe
|
|
||||||
uses a closing curly brace within the function and the character has
|
|
||||||
no leading spaces, BitBake produces a parsing error. If you use a
|
|
||||||
pair of curly braces in a shell function, the closing curly brace
|
|
||||||
must not be located at the start of the line without leading spaces.
|
|
||||||
|
|
||||||
Here is an example that causes BitBake to produce a parsing error::
|
|
||||||
|
|
||||||
fakeroot create_shar() {
|
|
||||||
cat << "EOF" > ${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.sh
|
|
||||||
usage()
|
|
||||||
{
|
|
||||||
echo "test"
|
|
||||||
###### The following "}" at the start of the line causes a parsing error ######
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
Writing the recipe this way avoids the error:
|
|
||||||
fakeroot create_shar() {
|
|
||||||
cat << "EOF" > ${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.sh
|
|
||||||
usage()
|
|
||||||
{
|
|
||||||
echo "test"
|
|
||||||
###### The following "}" with a leading space at the start of the line avoids the error ######
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
Locating and Parsing Recipes
|
|
||||||
============================
|
|
||||||
|
|
||||||
During the configuration phase, BitBake will have set
|
|
||||||
:term:`BBFILES`. BitBake now uses it to construct a
|
|
||||||
list of recipes to parse, along with any append files (``.bbappend``) to
|
|
||||||
apply. :term:`BBFILES` is a space-separated list of available files and
|
|
||||||
supports wildcards. An example would be::
|
|
||||||
|
|
||||||
BBFILES = "/path/to/bbfiles/*.bb /path/to/appends/*.bbappend"
|
|
||||||
|
|
||||||
BitBake parses each
|
|
||||||
recipe and append file located with :term:`BBFILES` and stores the values of
|
|
||||||
various variables into the datastore.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Append files are applied in the order they are encountered in BBFILES.
|
|
||||||
|
|
||||||
For each file, a fresh copy of the base configuration is made, then the
|
|
||||||
recipe is parsed line by line. Any inherit statements cause BitBake to
|
|
||||||
find and then parse class files (``.bbclass``) using
|
|
||||||
:term:`BBPATH` as the search path. Finally, BitBake
|
|
||||||
parses in order any append files found in :term:`BBFILES`.
|
|
||||||
|
|
||||||
One common convention is to use the recipe filename to define pieces of
|
|
||||||
metadata. For example, in ``bitbake.conf`` the recipe name and version
|
|
||||||
are used to set the variables :term:`PN` and
|
|
||||||
:term:`PV`::
|
|
||||||
|
|
||||||
PN = "${@bb.parse.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
|
|
||||||
PV = "${@bb.parse.vars_from_file(d.getVar('FILE', False),d)[1] or '1.0'}"
|
|
||||||
|
|
||||||
In this example, a recipe called "something_1.2.3.bb" would set
|
|
||||||
:term:`PN` to "something" and :term:`PV` to "1.2.3".
|
|
||||||
|
|
||||||
By the time parsing is complete for a recipe, BitBake has a list of
|
|
||||||
tasks that the recipe defines and a set of data consisting of keys and
|
|
||||||
values as well as dependency information about the tasks.
|
|
||||||
|
|
||||||
BitBake does not need all of this information. It only needs a small
|
|
||||||
subset of the information to make decisions about the recipe.
|
|
||||||
Consequently, BitBake caches the values in which it is interested and
|
|
||||||
does not store the rest of the information. Experience has shown it is
|
|
||||||
faster to re-parse the metadata than to try and write it out to the disk
|
|
||||||
and then reload it.
|
|
||||||
|
|
||||||
Where possible, subsequent BitBake commands reuse this cache of recipe
|
|
||||||
information. The validity of this cache is determined by first computing
|
|
||||||
a checksum of the base configuration data (see
|
|
||||||
:term:`BB_HASHCONFIG_IGNORE_VARS`) and
|
|
||||||
then checking if the checksum matches. If that checksum matches what is
|
|
||||||
in the cache and the recipe and class files have not changed, BitBake is
|
|
||||||
able to use the cache. BitBake then reloads the cached information about
|
|
||||||
the recipe instead of reparsing it from scratch.
|
|
||||||
|
|
||||||
Recipe file collections exist to allow the user to have multiple
|
|
||||||
repositories of ``.bb`` files that contain the same exact package. For
|
|
||||||
example, one could easily use them to make one's own local copy of an
|
|
||||||
upstream repository, but with custom modifications that one does not
|
|
||||||
want upstream. Here is an example::
|
|
||||||
|
|
||||||
BBFILES = "/stuff/openembedded/*/*.bb /stuff/openembedded.modified/*/*.bb"
|
|
||||||
BBFILE_COLLECTIONS = "upstream local"
|
|
||||||
BBFILE_PATTERN_upstream = "^/stuff/openembedded/"
|
|
||||||
BBFILE_PATTERN_local = "^/stuff/openembedded.modified/"
|
|
||||||
BBFILE_PRIORITY_upstream = "5"
|
|
||||||
BBFILE_PRIORITY_local = "10"
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
The layers mechanism is now the preferred method of collecting code.
|
|
||||||
While the collections code remains, its main use is to set layer
|
|
||||||
priorities and to deal with overlap (conflicts) between layers.
|
|
||||||
|
|
||||||
.. _bb-bitbake-providers:
|
|
||||||
|
|
||||||
Providers
|
|
||||||
=========
|
|
||||||
|
|
||||||
Assuming BitBake has been instructed to execute a target and that all
|
|
||||||
the recipe files have been parsed, BitBake starts to figure out how to
|
|
||||||
build the target. BitBake looks through the :term:`PROVIDES` list for each
|
|
||||||
of the recipes. A :term:`PROVIDES` list is the list of names by which the
|
|
||||||
recipe can be known. Each recipe's :term:`PROVIDES` list is created
|
|
||||||
implicitly through the recipe's :term:`PN` variable and
|
|
||||||
explicitly through the recipe's :term:`PROVIDES`
|
|
||||||
variable, which is optional.
|
|
||||||
|
|
||||||
When a recipe uses :term:`PROVIDES`, that recipe's functionality can be
|
|
||||||
found under an alternative name or names other than the implicit :term:`PN`
|
|
||||||
name. As an example, suppose a recipe named ``keyboard_1.0.bb``
|
|
||||||
contained the following::
|
|
||||||
|
|
||||||
PROVIDES += "fullkeyboard"
|
|
||||||
|
|
||||||
The :term:`PROVIDES`
|
|
||||||
list for this recipe becomes "keyboard", which is implicit, and
|
|
||||||
"fullkeyboard", which is explicit. Consequently, the functionality found
|
|
||||||
in ``keyboard_1.0.bb`` can be found under two different names.
|
|
||||||
|
|
||||||
.. _bb-bitbake-preferences:
|
|
||||||
|
|
||||||
Preferences
|
|
||||||
===========
|
|
||||||
|
|
||||||
The :term:`PROVIDES` list is only part of the solution for figuring out a
|
|
||||||
target's recipes. Because targets might have multiple providers, BitBake
|
|
||||||
needs to prioritize providers by determining provider preferences.
|
|
||||||
|
|
||||||
A common example in which a target has multiple providers is
|
|
||||||
"virtual/kernel", which is on the :term:`PROVIDES` list for each kernel
|
|
||||||
recipe. Each machine often selects the best kernel provider by using a
|
|
||||||
line similar to the following in the machine configuration file::
|
|
||||||
|
|
||||||
PREFERRED_PROVIDER_virtual/kernel = "linux-yocto"
|
|
||||||
|
|
||||||
The default :term:`PREFERRED_PROVIDER` is the provider
|
|
||||||
with the same name as the target. BitBake iterates through each target
|
|
||||||
it needs to build and resolves them and their dependencies using this
|
|
||||||
process.
|
|
||||||
|
|
||||||
Understanding how providers are chosen is made complicated by the fact
|
|
||||||
that multiple versions might exist for a given provider. BitBake
|
|
||||||
defaults to the highest version of a provider. Version comparisons are
|
|
||||||
made using the same method as Debian. You can use the
|
|
||||||
:term:`PREFERRED_VERSION` variable to
|
|
||||||
specify a particular version. You can influence the order by using the
|
|
||||||
:term:`DEFAULT_PREFERENCE` variable.
|
|
||||||
|
|
||||||
By default, files have a preference of "0". Setting
|
|
||||||
:term:`DEFAULT_PREFERENCE` to "-1" makes the recipe unlikely to be used
|
|
||||||
unless it is explicitly referenced. Setting :term:`DEFAULT_PREFERENCE` to
|
|
||||||
"1" makes it likely the recipe is used. :term:`PREFERRED_VERSION` overrides
|
|
||||||
any :term:`DEFAULT_PREFERENCE` setting. :term:`DEFAULT_PREFERENCE` is often used
|
|
||||||
to mark newer and more experimental recipe versions until they have
|
|
||||||
undergone sufficient testing to be considered stable.
|
|
||||||
|
|
||||||
When there are multiple "versions" of a given recipe, BitBake defaults
|
|
||||||
to selecting the most recent version, unless otherwise specified. If the
|
|
||||||
recipe in question has a
|
|
||||||
:term:`DEFAULT_PREFERENCE` set lower than
|
|
||||||
the other recipes (default is 0), then it will not be selected. This
|
|
||||||
allows the person or persons maintaining the repository of recipe files
|
|
||||||
to specify their preference for the default selected version.
|
|
||||||
Additionally, the user can specify their preferred version.
|
|
||||||
|
|
||||||
If the first recipe is named ``a_1.1.bb``, then the
|
|
||||||
:term:`PN` variable will be set to "a", and the
|
|
||||||
:term:`PV` variable will be set to 1.1.
|
|
||||||
|
|
||||||
Thus, if a recipe named ``a_1.2.bb`` exists, BitBake will choose 1.2 by
|
|
||||||
default. However, if you define the following variable in a ``.conf``
|
|
||||||
file that BitBake parses, you can change that preference::
|
|
||||||
|
|
||||||
PREFERRED_VERSION_a = "1.1"
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
It is common for a recipe to provide two versions -- a stable,
|
|
||||||
numbered (and preferred) version, and a version that is automatically
|
|
||||||
checked out from a source code repository that is considered more
|
|
||||||
"bleeding edge" but can be selected only explicitly.
|
|
||||||
|
|
||||||
For example, in the OpenEmbedded codebase, there is a standard,
|
|
||||||
versioned recipe file for BusyBox, ``busybox_1.22.1.bb``, but there
|
|
||||||
is also a Git-based version, ``busybox_git.bb``, which explicitly
|
|
||||||
contains the line ::
|
|
||||||
|
|
||||||
DEFAULT_PREFERENCE = "-1"
|
|
||||||
|
|
||||||
to ensure that the
|
|
||||||
numbered, stable version is always preferred unless the developer
|
|
||||||
selects otherwise.
|
|
||||||
|
|
||||||
.. _bb-bitbake-dependencies:
|
|
||||||
|
|
||||||
Dependencies
|
|
||||||
============
|
|
||||||
|
|
||||||
Each target BitBake builds consists of multiple tasks such as ``fetch``,
|
|
||||||
``unpack``, ``patch``, ``configure``, and ``compile``. For best
|
|
||||||
performance on multi-core systems, BitBake considers each task as an
|
|
||||||
independent entity with its own set of dependencies.
|
|
||||||
|
|
||||||
Dependencies are defined through several variables. You can find
|
|
||||||
information about variables BitBake uses in the
|
|
||||||
:doc:`bitbake-user-manual-ref-variables` near the end of this manual. At a
|
|
||||||
basic level, it is sufficient to know that BitBake uses the
|
|
||||||
:term:`DEPENDS` and
|
|
||||||
:term:`RDEPENDS` variables when calculating
|
|
||||||
dependencies.
|
|
||||||
|
|
||||||
For more information on how BitBake handles dependencies, see the
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-metadata:Dependencies`
|
|
||||||
section.
|
|
||||||
|
|
||||||
.. _ref-bitbake-tasklist:
|
|
||||||
|
|
||||||
The Task List
|
|
||||||
=============
|
|
||||||
|
|
||||||
Based on the generated list of providers and the dependency information,
|
|
||||||
BitBake can now calculate exactly what tasks it needs to run and in what
|
|
||||||
order it needs to run them. The
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-execution:executing tasks`
|
|
||||||
section has more information on how BitBake chooses which task to
|
|
||||||
execute next.
|
|
||||||
|
|
||||||
The build now starts with BitBake forking off threads up to the limit
|
|
||||||
set in the :term:`BB_NUMBER_THREADS`
|
|
||||||
variable. BitBake continues to fork threads as long as there are tasks
|
|
||||||
ready to run, those tasks have all their dependencies met, and the
|
|
||||||
thread threshold has not been exceeded.
|
|
||||||
|
|
||||||
It is worth noting that you can greatly speed up the build time by
|
|
||||||
properly setting the :term:`BB_NUMBER_THREADS` variable.
|
|
||||||
|
|
||||||
As each task completes, a timestamp is written to the directory
|
|
||||||
specified by the :term:`STAMP` variable. On subsequent
|
|
||||||
runs, BitBake looks in the build directory within ``tmp/stamps`` and
|
|
||||||
does not rerun tasks that are already completed unless a timestamp is
|
|
||||||
found to be invalid. Currently, invalid timestamps are only considered
|
|
||||||
on a per recipe file basis. So, for example, if the configure stamp has
|
|
||||||
a timestamp greater than the compile timestamp for a given target, then
|
|
||||||
the compile task would rerun. Running the compile task again, however,
|
|
||||||
has no effect on other providers that depend on that target.
|
|
||||||
|
|
||||||
The exact format of the stamps is partly configurable. In modern
|
|
||||||
versions of BitBake, a hash is appended to the stamp so that if the
|
|
||||||
configuration changes, the stamp becomes invalid and the task is
|
|
||||||
automatically rerun. This hash, or signature used, is governed by the
|
|
||||||
signature policy that is configured (see the
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-execution:checksums (signatures)`
|
|
||||||
section for information). It is also
|
|
||||||
possible to append extra metadata to the stamp using the
|
|
||||||
``[stamp-extra-info]`` task flag. For example, OpenEmbedded uses this
|
|
||||||
flag to make some tasks machine-specific.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Some tasks are marked as "nostamp" tasks. No timestamp file is
|
|
||||||
created when these tasks are run. Consequently, "nostamp" tasks are
|
|
||||||
always rerun.
|
|
||||||
|
|
||||||
For more information on tasks, see the
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-metadata:tasks` section.
|
|
||||||
|
|
||||||
Executing Tasks
|
|
||||||
===============
|
|
||||||
|
|
||||||
Tasks can be either a shell task or a Python task. For shell tasks,
|
|
||||||
BitBake writes a shell script to
|
|
||||||
``${``\ :term:`T`\ ``}/run.do_taskname.pid`` and then
|
|
||||||
executes the script. The generated shell script contains all the
|
|
||||||
exported variables, and the shell functions with all variables expanded.
|
|
||||||
Output from the shell script goes to the file
|
|
||||||
``${``\ :term:`T`\ ``}/log.do_taskname.pid``. Looking at the expanded shell functions in
|
|
||||||
the run file and the output in the log files is a useful debugging
|
|
||||||
technique.
|
|
||||||
|
|
||||||
For Python tasks, BitBake executes the task internally and logs
|
|
||||||
information to the controlling terminal. Future versions of BitBake will
|
|
||||||
write the functions to files similar to the way shell tasks are handled.
|
|
||||||
Logging will be handled in a way similar to shell tasks as well.
|
|
||||||
|
|
||||||
The order in which BitBake runs the tasks is controlled by its task
|
|
||||||
scheduler. It is possible to configure the scheduler and define custom
|
|
||||||
implementations for specific use cases. For more information, see these
|
|
||||||
variables that control the behavior:
|
|
||||||
|
|
||||||
- :term:`BB_SCHEDULER`
|
|
||||||
|
|
||||||
- :term:`BB_SCHEDULERS`
|
|
||||||
|
|
||||||
It is possible to have functions run before and after a task's main
|
|
||||||
function. This is done using the ``[prefuncs]`` and ``[postfuncs]``
|
|
||||||
flags of the task that lists the functions to run.
|
|
||||||
|
|
||||||
.. _checksums:
|
|
||||||
|
|
||||||
Checksums (Signatures)
|
|
||||||
======================
|
|
||||||
|
|
||||||
A checksum is a unique signature of a task's inputs. The signature of a
|
|
||||||
task can be used to determine if a task needs to be run. Because it is a
|
|
||||||
change in a task's inputs that triggers running the task, BitBake needs
|
|
||||||
to detect all the inputs to a given task. For shell tasks, this turns
|
|
||||||
out to be fairly easy because BitBake generates a "run" shell script for
|
|
||||||
each task and it is possible to create a checksum that gives you a good
|
|
||||||
idea of when the task's data changes.
|
|
||||||
|
|
||||||
To complicate the problem, some things should not be included in the
|
|
||||||
checksum. First, there is the actual specific build path of a given task
|
|
||||||
- the working directory. It does not matter if the working directory
|
|
||||||
changes because it should not affect the output for target packages. The
|
|
||||||
simplistic approach for excluding the working directory is to set it to
|
|
||||||
some fixed value and create the checksum for the "run" script. BitBake
|
|
||||||
goes one step better and uses the
|
|
||||||
:term:`BB_BASEHASH_IGNORE_VARS` variable
|
|
||||||
to define a list of variables that should never be included when
|
|
||||||
generating the signatures.
|
|
||||||
|
|
||||||
Another problem results from the "run" scripts containing functions that
|
|
||||||
might or might not get called. The incremental build solution contains
|
|
||||||
code that figures out dependencies between shell functions. This code is
|
|
||||||
used to prune the "run" scripts down to the minimum set, thereby
|
|
||||||
alleviating this problem and making the "run" scripts much more readable
|
|
||||||
as a bonus.
|
|
||||||
|
|
||||||
So far we have solutions for shell scripts. What about Python tasks? The
|
|
||||||
same approach applies even though these tasks are more difficult. The
|
|
||||||
process needs to figure out what variables a Python function accesses
|
|
||||||
and what functions it calls. Again, the incremental build solution
|
|
||||||
contains code that first figures out the variable and function
|
|
||||||
dependencies, and then creates a checksum for the data used as the input
|
|
||||||
to the task.
|
|
||||||
|
|
||||||
Like the working directory case, situations exist where dependencies
|
|
||||||
should be ignored. For these cases, you can instruct the build process
|
|
||||||
to ignore a dependency by using a line like the following::
|
|
||||||
|
|
||||||
PACKAGE_ARCHS[vardepsexclude] = "MACHINE"
|
|
||||||
|
|
||||||
This example ensures that the
|
|
||||||
``PACKAGE_ARCHS`` variable does not depend on the value of ``MACHINE``,
|
|
||||||
even if it does reference it.
|
|
||||||
|
|
||||||
Equally, there are cases where we need to add dependencies BitBake is
|
|
||||||
not able to find. You can accomplish this by using a line like the
|
|
||||||
following::
|
|
||||||
|
|
||||||
PACKAGE_ARCHS[vardeps] = "MACHINE"
|
|
||||||
|
|
||||||
This example explicitly
|
|
||||||
adds the ``MACHINE`` variable as a dependency for ``PACKAGE_ARCHS``.
|
|
||||||
|
|
||||||
Consider a case with in-line Python, for example, where BitBake is not
|
|
||||||
able to figure out dependencies. When running in debug mode (i.e. using
|
|
||||||
``-DDD``), BitBake produces output when it discovers something for which
|
|
||||||
it cannot figure out dependencies.
|
|
||||||
|
|
||||||
Thus far, this section has limited discussion to the direct inputs into
|
|
||||||
a task. Information based on direct inputs is referred to as the
|
|
||||||
"basehash" in the code. However, there is still the question of a task's
|
|
||||||
indirect inputs --- the things that were already built and present in the
|
|
||||||
build directory. The checksum (or signature) for a particular task needs
|
|
||||||
to add the hashes of all the tasks on which the particular task depends.
|
|
||||||
Choosing which dependencies to add is a policy decision. However, the
|
|
||||||
effect is to generate a master checksum that combines the basehash and
|
|
||||||
the hashes of the task's dependencies.
|
|
||||||
|
|
||||||
At the code level, there are a variety of ways both the basehash and the
|
|
||||||
dependent task hashes can be influenced. Within the BitBake
|
|
||||||
configuration file, we can give BitBake some extra information to help
|
|
||||||
it construct the basehash. The following statement effectively results
|
|
||||||
in a list of global variable dependency excludes --- variables never
|
|
||||||
included in any checksum. This example uses variables from OpenEmbedded
|
|
||||||
to help illustrate the concept::
|
|
||||||
|
|
||||||
BB_BASEHASH_IGNORE_VARS ?= "TMPDIR FILE PATH PWD BB_TASKHASH BBPATH DL_DIR \
|
|
||||||
SSTATE_DIR THISDIR FILESEXTRAPATHS FILE_DIRNAME HOME LOGNAME SHELL \
|
|
||||||
USER FILESPATH STAGING_DIR_HOST STAGING_DIR_TARGET COREBASE PRSERV_HOST \
|
|
||||||
PRSERV_DUMPDIR PRSERV_DUMPFILE PRSERV_LOCKDOWN PARALLEL_MAKE \
|
|
||||||
CCACHE_DIR EXTERNAL_TOOLCHAIN CCACHE CCACHE_DISABLE LICENSE_PATH SDKPKGSUFFIX"
|
|
||||||
|
|
||||||
The previous example excludes the work directory, which is part of
|
|
||||||
``TMPDIR``.
|
|
||||||
|
|
||||||
The rules for deciding which hashes of dependent tasks to include
|
|
||||||
through dependency chains are more complex and are generally
|
|
||||||
accomplished with a Python function. The code in
|
|
||||||
``meta/lib/oe/sstatesig.py`` shows two examples of this and also
|
|
||||||
illustrates how you can insert your own policy into the system if so
|
|
||||||
desired. This file defines the basic signature generator
|
|
||||||
OpenEmbedded-Core uses: "OEBasicHash". By default, there
|
|
||||||
is a dummy "noop" signature handler enabled in BitBake. This means that
|
|
||||||
behavior is unchanged from previous versions. ``OE-Core`` uses the
|
|
||||||
"OEBasicHash" signature handler by default through this setting in the
|
|
||||||
``bitbake.conf`` file::
|
|
||||||
|
|
||||||
BB_SIGNATURE_HANDLER ?= "OEBasicHash"
|
|
||||||
|
|
||||||
The main feature of the "OEBasicHash" :term:`BB_SIGNATURE_HANDLER` is that
|
|
||||||
it adds the task hash to the stamp files. Thanks to this, any metadata
|
|
||||||
change will change the task hash, automatically causing the task to be run
|
|
||||||
again. This removes the need to bump :term:`PR` values, and changes to
|
|
||||||
metadata automatically ripple across the build.
|
|
||||||
|
|
||||||
It is also worth noting that the end result of signature
|
|
||||||
generators is to make some dependency and hash information available to
|
|
||||||
the build. This information includes:
|
|
||||||
|
|
||||||
- ``BB_BASEHASH_task-``\ *taskname*: The base hashes for each task in the
|
|
||||||
recipe.
|
|
||||||
|
|
||||||
- ``BB_BASEHASH_``\ *filename:taskname*: The base hashes for each
|
|
||||||
dependent task.
|
|
||||||
|
|
||||||
- :term:`BB_TASKHASH`: The hash of the currently running task.
|
|
||||||
|
|
||||||
It is worth noting that BitBake's "-S" option lets you debug BitBake's
|
|
||||||
processing of signatures. The options passed to -S allow different
|
|
||||||
debugging modes to be used, either using BitBake's own debug functions
|
|
||||||
or possibly those defined in the metadata/signature handler itself. The
|
|
||||||
simplest parameter to pass is "none", which causes a set of signature
|
|
||||||
information to be written out into ``STAMPS_DIR`` corresponding to the
|
|
||||||
targets specified. The other currently available parameter is
|
|
||||||
"printdiff", which causes BitBake to try to establish the most recent
|
|
||||||
signature match it can (e.g. in the sstate cache) and then run
|
|
||||||
compare the matched signatures to determine the stamps and delta
|
|
||||||
where these two stamp trees diverge. This can be used to determine why
|
|
||||||
tasks need to be re-run in situations where that is not expected.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
It is likely that future versions of BitBake will provide other
|
|
||||||
signature handlers triggered through additional "-S" parameters.
|
|
||||||
|
|
||||||
You can find more information on checksum metadata in the
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-metadata:task checksums and setscene`
|
|
||||||
section.
|
|
||||||
|
|
||||||
Setscene
|
|
||||||
========
|
|
||||||
|
|
||||||
The setscene process enables BitBake to handle "pre-built" artifacts.
|
|
||||||
The ability to handle and reuse these artifacts allows BitBake the
|
|
||||||
luxury of not having to build something from scratch every time.
|
|
||||||
Instead, BitBake can use, when possible, existing build artifacts.
|
|
||||||
|
|
||||||
BitBake needs to have reliable data indicating whether or not an
|
|
||||||
artifact is compatible. Signatures, described in the previous section,
|
|
||||||
provide an ideal way of representing whether an artifact is compatible.
|
|
||||||
If a signature is the same, an object can be reused.
|
|
||||||
|
|
||||||
If an object can be reused, the problem then becomes how to replace a
|
|
||||||
given task or set of tasks with the pre-built artifact. BitBake solves
|
|
||||||
the problem with the "setscene" process.
|
|
||||||
|
|
||||||
When BitBake is asked to build a given target, before building anything,
|
|
||||||
it first asks whether cached information is available for any of the
|
|
||||||
targets it's building, or any of the intermediate targets. If cached
|
|
||||||
information is available, BitBake uses this information instead of
|
|
||||||
running the main tasks.
|
|
||||||
|
|
||||||
BitBake first calls the function defined by the
|
|
||||||
:term:`BB_HASHCHECK_FUNCTION` variable
|
|
||||||
with a list of tasks and corresponding hashes it wants to build. This
|
|
||||||
function is designed to be fast and returns a list of the tasks for
|
|
||||||
which it believes in can obtain artifacts.
|
|
||||||
|
|
||||||
Next, for each of the tasks that were returned as possibilities, BitBake
|
|
||||||
executes a setscene version of the task that the possible artifact
|
|
||||||
covers. Setscene versions of a task have the string "_setscene" appended
|
|
||||||
to the task name. So, for example, the task with the name ``xxx`` has a
|
|
||||||
setscene task named ``xxx_setscene``. The setscene version of the task
|
|
||||||
executes and provides the necessary artifacts returning either success
|
|
||||||
or failure.
|
|
||||||
|
|
||||||
As previously mentioned, an artifact can cover more than one task. For
|
|
||||||
example, it is pointless to obtain a compiler if you already have the
|
|
||||||
compiled binary. To handle this, BitBake calls the
|
|
||||||
:term:`BB_SETSCENE_DEPVALID` function for
|
|
||||||
each successful setscene task to know whether or not it needs to obtain
|
|
||||||
the dependencies of that task.
|
|
||||||
|
|
||||||
You can find more information on setscene metadata in the
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-metadata:task checksums and setscene`
|
|
||||||
section.
|
|
||||||
|
|
||||||
Logging
|
|
||||||
=======
|
|
||||||
|
|
||||||
In addition to the standard command line option to control how verbose
|
|
||||||
builds are when execute, bitbake also supports user defined
|
|
||||||
configuration of the `Python
|
|
||||||
logging <https://docs.python.org/3/library/logging.html>`__ facilities
|
|
||||||
through the :term:`BB_LOGCONFIG` variable. This
|
|
||||||
variable defines a JSON or YAML `logging
|
|
||||||
configuration <https://docs.python.org/3/library/logging.config.html>`__
|
|
||||||
that will be intelligently merged into the default configuration. The
|
|
||||||
logging configuration is merged using the following rules:
|
|
||||||
|
|
||||||
- The user defined configuration will completely replace the default
|
|
||||||
configuration if top level key ``bitbake_merge`` is set to the value
|
|
||||||
``False``. In this case, all other rules are ignored.
|
|
||||||
|
|
||||||
- The user configuration must have a top level ``version`` which must
|
|
||||||
match the value of the default configuration.
|
|
||||||
|
|
||||||
- Any keys defined in the ``handlers``, ``formatters``, or ``filters``,
|
|
||||||
will be merged into the same section in the default configuration,
|
|
||||||
with the user specified keys taking replacing a default one if there
|
|
||||||
is a conflict. In practice, this means that if both the default
|
|
||||||
configuration and user configuration specify a handler named
|
|
||||||
``myhandler``, the user defined one will replace the default. To
|
|
||||||
prevent the user from inadvertently replacing a default handler,
|
|
||||||
formatter, or filter, all of the default ones are named with a prefix
|
|
||||||
of "``BitBake.``"
|
|
||||||
|
|
||||||
- If a logger is defined by the user with the key ``bitbake_merge`` set
|
|
||||||
to ``False``, that logger will be completely replaced by user
|
|
||||||
configuration. In this case, no other rules will apply to that
|
|
||||||
logger.
|
|
||||||
|
|
||||||
- All user defined ``filter`` and ``handlers`` properties for a given
|
|
||||||
logger will be merged with corresponding properties from the default
|
|
||||||
logger. For example, if the user configuration adds a filter called
|
|
||||||
``myFilter`` to the ``BitBake.SigGen``, and the default configuration
|
|
||||||
adds a filter called ``BitBake.defaultFilter``, both filters will be
|
|
||||||
applied to the logger
|
|
||||||
|
|
||||||
As a first example, you can create a ``hashequiv.json`` user logging
|
|
||||||
configuration file to log all Hash Equivalence related messages of ``VERBOSE``
|
|
||||||
or higher priority to a file called ``hashequiv.log``::
|
|
||||||
|
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"handlers": {
|
|
||||||
"autobuilderlog": {
|
|
||||||
"class": "logging.FileHandler",
|
|
||||||
"formatter": "logfileFormatter",
|
|
||||||
"level": "DEBUG",
|
|
||||||
"filename": "hashequiv.log",
|
|
||||||
"mode": "w"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"formatters": {
|
|
||||||
"logfileFormatter": {
|
|
||||||
"format": "%(name)s: %(levelname)s: %(message)s"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"loggers": {
|
|
||||||
"BitBake.SigGen.HashEquiv": {
|
|
||||||
"level": "VERBOSE",
|
|
||||||
"handlers": ["autobuilderlog"]
|
|
||||||
},
|
|
||||||
"BitBake.RunQueue.HashEquiv": {
|
|
||||||
"level": "VERBOSE",
|
|
||||||
"handlers": ["autobuilderlog"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Then set the :term:`BB_LOGCONFIG` variable in ``conf/local.conf``::
|
|
||||||
|
|
||||||
BB_LOGCONFIG = "hashequiv.json"
|
|
||||||
|
|
||||||
Another example is this ``warn.json`` file to log all ``WARNING`` and
|
|
||||||
higher priority messages to a ``warn.log`` file::
|
|
||||||
|
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"formatters": {
|
|
||||||
"warnlogFormatter": {
|
|
||||||
"()": "bb.msg.BBLogFormatter",
|
|
||||||
"format": "%(levelname)s: %(message)s"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"handlers": {
|
|
||||||
"warnlog": {
|
|
||||||
"class": "logging.FileHandler",
|
|
||||||
"formatter": "warnlogFormatter",
|
|
||||||
"level": "WARNING",
|
|
||||||
"filename": "warn.log"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"loggers": {
|
|
||||||
"BitBake": {
|
|
||||||
"handlers": ["warnlog"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"@disable_existing_loggers": false
|
|
||||||
}
|
|
||||||
|
|
||||||
Note that BitBake's helper classes for structured logging are implemented in
|
|
||||||
``lib/bb/msg.py``.
|
|
||||||
@@ -0,0 +1,932 @@
|
|||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<chapter id="bitbake-user-manual-execution">
|
||||||
|
<title>Execution</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The primary purpose for running BitBake is to produce some kind
|
||||||
|
of output such as a single installable package, a kernel, a software
|
||||||
|
development kit, or even a full, board-specific bootable Linux image,
|
||||||
|
complete with bootloader, kernel, and root filesystem.
|
||||||
|
Of course, you can execute the <filename>bitbake</filename>
|
||||||
|
command with options that cause it to execute single tasks,
|
||||||
|
compile single recipe files, capture or clear data, or simply
|
||||||
|
return information about the execution environment.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This chapter describes BitBake's execution process from start
|
||||||
|
to finish when you use it to create an image.
|
||||||
|
The execution process is launched using the following command
|
||||||
|
form:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake <replaceable>target</replaceable>
|
||||||
|
</literallayout>
|
||||||
|
For information on the BitBake command and its options,
|
||||||
|
see
|
||||||
|
"<link linkend='bitbake-user-manual-command'>The BitBake Command</link>"
|
||||||
|
section.
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
Prior to executing BitBake, you should take advantage of available
|
||||||
|
parallel thread execution on your build host by setting the
|
||||||
|
<link linkend='var-bb-BB_NUMBER_THREADS'><filename>BB_NUMBER_THREADS</filename></link>
|
||||||
|
variable in your project's <filename>local.conf</filename>
|
||||||
|
configuration file.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A common method to determine this value for your build host is to run
|
||||||
|
the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ grep processor /proc/cpuinfo
|
||||||
|
</literallayout>
|
||||||
|
This command returns the number of processors, which takes into
|
||||||
|
account hyper-threading.
|
||||||
|
Thus, a quad-core build host with hyper-threading most likely
|
||||||
|
shows eight processors, which is the value you would then assign to
|
||||||
|
<filename>BB_NUMBER_THREADS</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A possibly simpler solution is that some Linux distributions
|
||||||
|
(e.g. Debian and Ubuntu) provide the <filename>ncpus</filename> command.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id='parsing-the-base-configuration-metadata'>
|
||||||
|
<title>Parsing the Base Configuration Metadata</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The first thing BitBake does is parse base configuration
|
||||||
|
metadata.
|
||||||
|
Base configuration metadata consists of your project's
|
||||||
|
<filename>bblayers.conf</filename> file to determine what
|
||||||
|
layers BitBake needs to recognize, all necessary
|
||||||
|
<filename>layer.conf</filename> files (one from each layer),
|
||||||
|
and <filename>bitbake.conf</filename>.
|
||||||
|
The data itself is of various types:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><emphasis>Recipes:</emphasis>
|
||||||
|
Details about particular pieces of software.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Class Data:</emphasis>
|
||||||
|
An abstraction of common build information
|
||||||
|
(e.g. how to build a Linux kernel).
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Configuration Data:</emphasis>
|
||||||
|
Machine-specific settings, policy decisions,
|
||||||
|
and so forth.
|
||||||
|
Configuration data acts as the glue to bind everything
|
||||||
|
together.</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <filename>layer.conf</filename> files are used to
|
||||||
|
construct key variables such as
|
||||||
|
<link linkend='var-bb-BBPATH'><filename>BBPATH</filename></link>
|
||||||
|
and
|
||||||
|
<link linkend='var-bb-BBFILES'><filename>BBFILES</filename></link>.
|
||||||
|
<filename>BBPATH</filename> is used to search for
|
||||||
|
configuration and class files under the
|
||||||
|
<filename>conf</filename> and <filename>classes</filename>
|
||||||
|
directories, respectively.
|
||||||
|
<filename>BBFILES</filename> is used to locate both recipe
|
||||||
|
and recipe append files
|
||||||
|
(<filename>.bb</filename> and <filename>.bbappend</filename>).
|
||||||
|
If there is no <filename>bblayers.conf</filename> file,
|
||||||
|
it is assumed the user has set the <filename>BBPATH</filename>
|
||||||
|
and <filename>BBFILES</filename> directly in the environment.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Next, the <filename>bitbake.conf</filename> file is located
|
||||||
|
using the <filename>BBPATH</filename> variable that was
|
||||||
|
just constructed.
|
||||||
|
The <filename>bitbake.conf</filename> file may also include other
|
||||||
|
configuration files using the
|
||||||
|
<filename>include</filename> or
|
||||||
|
<filename>require</filename> directives.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Prior to parsing configuration files, Bitbake looks
|
||||||
|
at certain variables, including:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
<link linkend='var-bb-BB_ENV_WHITELIST'><filename>BB_ENV_WHITELIST</filename></link>
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
<link linkend='var-bb-BB_ENV_EXTRAWHITE'><filename>BB_ENV_EXTRAWHITE</filename></link>
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
<link linkend='var-bb-BB_PRESERVE_ENV'><filename>BB_PRESERVE_ENV</filename></link>
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
<link linkend='var-bb-BB_ORIGENV'><filename>BB_ORIGENV</filename></link>
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
<link linkend='var-bb-BITBAKE_UI'><filename>BITBAKE_UI</filename></link>
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
The first four variables in this list relate to how BitBake treats shell
|
||||||
|
environment variables during task execution.
|
||||||
|
By default, BitBake cleans the environment variables and provides tight
|
||||||
|
control over the shell execution environment.
|
||||||
|
However, through the use of these first four variables, you can
|
||||||
|
apply your control regarding the
|
||||||
|
environment variables allowed to be used by BitBake in the shell
|
||||||
|
during execution of tasks.
|
||||||
|
See the
|
||||||
|
"<link linkend='passing-information-into-the-build-task-environment'>Passing Information Into the Build Task Environment</link>"
|
||||||
|
section and the information about these variables in the
|
||||||
|
variable glossary for more information on how they work and
|
||||||
|
on how to use them.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The base configuration metadata is global
|
||||||
|
and therefore affects all recipes and tasks that are executed.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake first searches the current working directory for an
|
||||||
|
optional <filename>conf/bblayers.conf</filename> configuration file.
|
||||||
|
This file is expected to contain a
|
||||||
|
<link linkend='var-bb-BBLAYERS'><filename>BBLAYERS</filename></link>
|
||||||
|
variable that is a space-delimited list of 'layer' directories.
|
||||||
|
Recall that if BitBake cannot find a <filename>bblayers.conf</filename>
|
||||||
|
file, then it is assumed the user has set the <filename>BBPATH</filename>
|
||||||
|
and <filename>BBFILES</filename> variables directly in the environment.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For each directory (layer) in this list, a <filename>conf/layer.conf</filename>
|
||||||
|
file is located and parsed with the
|
||||||
|
<link linkend='var-bb-LAYERDIR'><filename>LAYERDIR</filename></link>
|
||||||
|
variable being set to the directory where the layer was found.
|
||||||
|
The idea is these files automatically set up
|
||||||
|
<link linkend='var-bb-BBPATH'><filename>BBPATH</filename></link>
|
||||||
|
and other variables correctly for a given build directory.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake then expects to find the <filename>conf/bitbake.conf</filename>
|
||||||
|
file somewhere in the user-specified <filename>BBPATH</filename>.
|
||||||
|
That configuration file generally has include directives to pull
|
||||||
|
in any other metadata such as files specific to the architecture,
|
||||||
|
the machine, the local environment, and so forth.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Only variable definitions and include directives are allowed
|
||||||
|
in BitBake <filename>.conf</filename> files.
|
||||||
|
Some variables directly influence BitBake's behavior.
|
||||||
|
These variables might have been set from the environment
|
||||||
|
depending on the environment variables previously
|
||||||
|
mentioned or set in the configuration files.
|
||||||
|
The
|
||||||
|
"<link linkend='ref-bb-variables-glos'>Variables Glossary</link>"
|
||||||
|
chapter presents a full list of variables.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
After parsing configuration files, BitBake uses its rudimentary
|
||||||
|
inheritance mechanism, which is through class files, to inherit
|
||||||
|
some standard classes.
|
||||||
|
BitBake parses a class when the inherit directive responsible
|
||||||
|
for getting that class is encountered.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <filename>base.bbclass</filename> file is always included.
|
||||||
|
Other classes that are specified in the configuration using the
|
||||||
|
<link linkend='var-bb-INHERIT'><filename>INHERIT</filename></link>
|
||||||
|
variable are also included.
|
||||||
|
BitBake searches for class files in a
|
||||||
|
<filename>classes</filename> subdirectory under
|
||||||
|
the paths in <filename>BBPATH</filename> in the same way as
|
||||||
|
configuration files.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A good way to get an idea of the configuration files and
|
||||||
|
the class files used in your execution environment is to
|
||||||
|
run the following BitBake command:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake -e > mybb.log
|
||||||
|
</literallayout>
|
||||||
|
Examining the top of the <filename>mybb.log</filename>
|
||||||
|
shows you the many configuration files and class files
|
||||||
|
used in your execution environment.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
You need to be aware of how BitBake parses curly braces.
|
||||||
|
If a recipe uses a closing curly brace within the function and
|
||||||
|
the character has no leading spaces, BitBake produces a parsing
|
||||||
|
error.
|
||||||
|
If you use a pair of curly braces in a shell function, the
|
||||||
|
closing curly brace must not be located at the start of the line
|
||||||
|
without leading spaces.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Here is an example that causes BitBake to produce a parsing
|
||||||
|
error:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
fakeroot create_shar() {
|
||||||
|
cat << "EOF" > ${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.sh
|
||||||
|
usage()
|
||||||
|
{
|
||||||
|
echo "test"
|
||||||
|
###### The following "}" at the start of the line causes a parsing error ######
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
</literallayout>
|
||||||
|
Writing the recipe this way avoids the error:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
fakeroot create_shar() {
|
||||||
|
cat << "EOF" > ${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.sh
|
||||||
|
usage()
|
||||||
|
{
|
||||||
|
echo "test"
|
||||||
|
######The following "}" with a leading space at the start of the line avoids the error ######
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='locating-and-parsing-recipes'>
|
||||||
|
<title>Locating and Parsing Recipes</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
During the configuration phase, BitBake will have set
|
||||||
|
<link linkend='var-bb-BBFILES'><filename>BBFILES</filename></link>.
|
||||||
|
BitBake now uses it to construct a list of recipes to parse,
|
||||||
|
along with any append files (<filename>.bbappend</filename>)
|
||||||
|
to apply.
|
||||||
|
<filename>BBFILES</filename> is a space-separated list of
|
||||||
|
available files and supports wildcards.
|
||||||
|
An example would be:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
BBFILES = "/path/to/bbfiles/*.bb /path/to/appends/*.bbappend"
|
||||||
|
</literallayout>
|
||||||
|
BitBake parses each recipe and append file located
|
||||||
|
with <filename>BBFILES</filename> and stores the values of
|
||||||
|
various variables into the datastore.
|
||||||
|
<note>
|
||||||
|
Append files are applied in the order they are encountered in
|
||||||
|
<filename>BBFILES</filename>.
|
||||||
|
</note>
|
||||||
|
For each file, a fresh copy of the base configuration is
|
||||||
|
made, then the recipe is parsed line by line.
|
||||||
|
Any inherit statements cause BitBake to find and
|
||||||
|
then parse class files (<filename>.bbclass</filename>)
|
||||||
|
using
|
||||||
|
<link linkend='var-bb-BBPATH'><filename>BBPATH</filename></link>
|
||||||
|
as the search path.
|
||||||
|
Finally, BitBake parses in order any append files found in
|
||||||
|
<filename>BBFILES</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
One common convention is to use the recipe filename to define
|
||||||
|
pieces of metadata.
|
||||||
|
For example, in <filename>bitbake.conf</filename> the recipe
|
||||||
|
name and version are used to set the variables
|
||||||
|
<link linkend='var-bb-PN'><filename>PN</filename></link> and
|
||||||
|
<link linkend='var-bb-PV'><filename>PV</filename></link>:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
PN = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
|
||||||
|
PV = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[1] or '1.0'}"
|
||||||
|
</literallayout>
|
||||||
|
In this example, a recipe called "something_1.2.3.bb" would set
|
||||||
|
<filename>PN</filename> to "something" and
|
||||||
|
<filename>PV</filename> to "1.2.3".
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
By the time parsing is complete for a recipe, BitBake
|
||||||
|
has a list of tasks that the recipe defines and a set of
|
||||||
|
data consisting of keys and values as well as
|
||||||
|
dependency information about the tasks.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake does not need all of this information.
|
||||||
|
It only needs a small subset of the information to make
|
||||||
|
decisions about the recipe.
|
||||||
|
Consequently, BitBake caches the values in which it is
|
||||||
|
interested and does not store the rest of the information.
|
||||||
|
Experience has shown it is faster to re-parse the metadata than to
|
||||||
|
try and write it out to the disk and then reload it.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Where possible, subsequent BitBake commands reuse this cache of
|
||||||
|
recipe information.
|
||||||
|
The validity of this cache is determined by first computing a
|
||||||
|
checksum of the base configuration data (see
|
||||||
|
<link linkend='var-bb-BB_HASHCONFIG_WHITELIST'><filename>BB_HASHCONFIG_WHITELIST</filename></link>)
|
||||||
|
and then checking if the checksum matches.
|
||||||
|
If that checksum matches what is in the cache and the recipe
|
||||||
|
and class files have not changed, Bitbake is able to use
|
||||||
|
the cache.
|
||||||
|
BitBake then reloads the cached information about the recipe
|
||||||
|
instead of reparsing it from scratch.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Recipe file collections exist to allow the user to
|
||||||
|
have multiple repositories of
|
||||||
|
<filename>.bb</filename> files that contain the same
|
||||||
|
exact package.
|
||||||
|
For example, one could easily use them to make one's
|
||||||
|
own local copy of an upstream repository, but with
|
||||||
|
custom modifications that one does not want upstream.
|
||||||
|
Here is an example:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
BBFILES = "/stuff/openembedded/*/*.bb /stuff/openembedded.modified/*/*.bb"
|
||||||
|
BBFILE_COLLECTIONS = "upstream local"
|
||||||
|
BBFILE_PATTERN_upstream = "^/stuff/openembedded/"
|
||||||
|
BBFILE_PATTERN_local = "^/stuff/openembedded.modified/"
|
||||||
|
BBFILE_PRIORITY_upstream = "5"
|
||||||
|
BBFILE_PRIORITY_local = "10"
|
||||||
|
</literallayout>
|
||||||
|
<note>
|
||||||
|
The layers mechanism is now the preferred method of collecting
|
||||||
|
code.
|
||||||
|
While the collections code remains, its main use is to set layer
|
||||||
|
priorities and to deal with overlap (conflicts) between layers.
|
||||||
|
</note>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bb-bitbake-providers'>
|
||||||
|
<title>Providers</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Assuming BitBake has been instructed to execute a target
|
||||||
|
and that all the recipe files have been parsed, BitBake
|
||||||
|
starts to figure out how to build the target.
|
||||||
|
BitBake looks through the <filename>PROVIDES</filename> list
|
||||||
|
for each of the recipes.
|
||||||
|
A <filename>PROVIDES</filename> list is the list of names by which
|
||||||
|
the recipe can be known.
|
||||||
|
Each recipe's <filename>PROVIDES</filename> list is created
|
||||||
|
implicitly through the recipe's
|
||||||
|
<link linkend='var-bb-PN'><filename>PN</filename></link> variable
|
||||||
|
and explicitly through the recipe's
|
||||||
|
<link linkend='var-bb-PROVIDES'><filename>PROVIDES</filename></link>
|
||||||
|
variable, which is optional.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When a recipe uses <filename>PROVIDES</filename>, that recipe's
|
||||||
|
functionality can be found under an alternative name or names other
|
||||||
|
than the implicit <filename>PN</filename> name.
|
||||||
|
As an example, suppose a recipe named <filename>keyboard_1.0.bb</filename>
|
||||||
|
contained the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
PROVIDES += "fullkeyboard"
|
||||||
|
</literallayout>
|
||||||
|
The <filename>PROVIDES</filename> list for this recipe becomes
|
||||||
|
"keyboard", which is implicit, and "fullkeyboard", which is explicit.
|
||||||
|
Consequently, the functionality found in
|
||||||
|
<filename>keyboard_1.0.bb</filename> can be found under two
|
||||||
|
different names.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bb-bitbake-preferences'>
|
||||||
|
<title>Preferences</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <filename>PROVIDES</filename> list is only part of the solution
|
||||||
|
for figuring out a target's recipes.
|
||||||
|
Because targets might have multiple providers, BitBake needs
|
||||||
|
to prioritize providers by determining provider preferences.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A common example in which a target has multiple providers
|
||||||
|
is "virtual/kernel", which is on the
|
||||||
|
<filename>PROVIDES</filename> list for each kernel recipe.
|
||||||
|
Each machine often selects the best kernel provider by using a
|
||||||
|
line similar to the following in the machine configuration file:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
PREFERRED_PROVIDER_virtual/kernel = "linux-yocto"
|
||||||
|
</literallayout>
|
||||||
|
The default
|
||||||
|
<link linkend='var-bb-PREFERRED_PROVIDER'><filename>PREFERRED_PROVIDER</filename></link>
|
||||||
|
is the provider with the same name as the target.
|
||||||
|
Bitbake iterates through each target it needs to build and
|
||||||
|
resolves them and their dependencies using this process.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Understanding how providers are chosen is made complicated by the fact
|
||||||
|
that multiple versions might exist for a given provider.
|
||||||
|
BitBake defaults to the highest version of a provider.
|
||||||
|
Version comparisons are made using the same method as Debian.
|
||||||
|
You can use the
|
||||||
|
<link linkend='var-bb-PREFERRED_VERSION'><filename>PREFERRED_VERSION</filename></link>
|
||||||
|
variable to specify a particular version.
|
||||||
|
You can influence the order by using the
|
||||||
|
<link linkend='var-bb-DEFAULT_PREFERENCE'><filename>DEFAULT_PREFERENCE</filename></link>
|
||||||
|
variable.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
By default, files have a preference of "0".
|
||||||
|
Setting <filename>DEFAULT_PREFERENCE</filename> to "-1" makes the
|
||||||
|
recipe unlikely to be used unless it is explicitly referenced.
|
||||||
|
Setting <filename>DEFAULT_PREFERENCE</filename> to "1" makes it
|
||||||
|
likely the recipe is used.
|
||||||
|
<filename>PREFERRED_VERSION</filename> overrides any
|
||||||
|
<filename>DEFAULT_PREFERENCE</filename> setting.
|
||||||
|
<filename>DEFAULT_PREFERENCE</filename> is often used to mark newer
|
||||||
|
and more experimental recipe versions until they have undergone
|
||||||
|
sufficient testing to be considered stable.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When there are multiple “versions” of a given recipe,
|
||||||
|
BitBake defaults to selecting the most recent
|
||||||
|
version, unless otherwise specified.
|
||||||
|
If the recipe in question has a
|
||||||
|
<link linkend='var-bb-DEFAULT_PREFERENCE'><filename>DEFAULT_PREFERENCE</filename></link>
|
||||||
|
set lower than the other recipes (default is 0), then
|
||||||
|
it will not be selected.
|
||||||
|
This allows the person or persons maintaining
|
||||||
|
the repository of recipe files to specify
|
||||||
|
their preference for the default selected version.
|
||||||
|
Additionally, the user can specify their preferred version.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If the first recipe is named <filename>a_1.1.bb</filename>, then the
|
||||||
|
<link linkend='var-bb-PN'><filename>PN</filename></link> variable
|
||||||
|
will be set to “a”, and the
|
||||||
|
<link linkend='var-bb-PV'><filename>PV</filename></link>
|
||||||
|
variable will be set to 1.1.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Thus, if a recipe named <filename>a_1.2.bb</filename> exists, BitBake
|
||||||
|
will choose 1.2 by default.
|
||||||
|
However, if you define the following variable in a
|
||||||
|
<filename>.conf</filename> file that BitBake parses, you
|
||||||
|
can change that preference:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
PREFERRED_VERSION_a = "1.1"
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
It is common for a recipe to provide two versions -- a stable,
|
||||||
|
numbered (and preferred) version, and a version that is
|
||||||
|
automatically checked out from a source code repository that
|
||||||
|
is considered more "bleeding edge" but can be selected only
|
||||||
|
explicitly.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For example, in the OpenEmbedded codebase, there is a standard,
|
||||||
|
versioned recipe file for BusyBox,
|
||||||
|
<filename>busybox_1.22.1.bb</filename>,
|
||||||
|
but there is also a Git-based version,
|
||||||
|
<filename>busybox_git.bb</filename>, which explicitly contains the line
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
DEFAULT_PREFERENCE = "-1"
|
||||||
|
</literallayout>
|
||||||
|
to ensure that the numbered, stable version is always preferred
|
||||||
|
unless the developer selects otherwise.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bb-bitbake-dependencies'>
|
||||||
|
<title>Dependencies</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Each target BitBake builds consists of multiple tasks such as
|
||||||
|
<filename>fetch</filename>, <filename>unpack</filename>,
|
||||||
|
<filename>patch</filename>, <filename>configure</filename>,
|
||||||
|
and <filename>compile</filename>.
|
||||||
|
For best performance on multi-core systems, BitBake considers each
|
||||||
|
task as an independent
|
||||||
|
entity with its own set of dependencies.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Dependencies are defined through several variables.
|
||||||
|
You can find information about variables BitBake uses in
|
||||||
|
the <link linkend='ref-bb-variables-glos'>Variables Glossary</link>
|
||||||
|
near the end of this manual.
|
||||||
|
At a basic level, it is sufficient to know that BitBake uses the
|
||||||
|
<link linkend='var-bb-DEPENDS'><filename>DEPENDS</filename></link> and
|
||||||
|
<link linkend='var-bb-RDEPENDS'><filename>RDEPENDS</filename></link> variables when
|
||||||
|
calculating dependencies.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For more information on how BitBake handles dependencies, see the
|
||||||
|
"<link linkend='dependencies'>Dependencies</link>" section.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='ref-bitbake-tasklist'>
|
||||||
|
<title>The Task List</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Based on the generated list of providers and the dependency information,
|
||||||
|
BitBake can now calculate exactly what tasks it needs to run and in what
|
||||||
|
order it needs to run them.
|
||||||
|
The
|
||||||
|
"<link linkend='executing-tasks'>Executing Tasks</link>" section has more
|
||||||
|
information on how BitBake chooses which task to execute next.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The build now starts with BitBake forking off threads up to the limit set in the
|
||||||
|
<link linkend='var-bb-BB_NUMBER_THREADS'><filename>BB_NUMBER_THREADS</filename></link>
|
||||||
|
variable.
|
||||||
|
BitBake continues to fork threads as long as there are tasks ready to run,
|
||||||
|
those tasks have all their dependencies met, and the thread threshold has not been
|
||||||
|
exceeded.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
It is worth noting that you can greatly speed up the build time by properly setting
|
||||||
|
the <filename>BB_NUMBER_THREADS</filename> variable.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As each task completes, a timestamp is written to the directory specified by the
|
||||||
|
<link linkend='var-bb-STAMP'><filename>STAMP</filename></link> variable.
|
||||||
|
On subsequent runs, BitBake looks in the build directory within
|
||||||
|
<filename>tmp/stamps</filename> and does not rerun
|
||||||
|
tasks that are already completed unless a timestamp is found to be invalid.
|
||||||
|
Currently, invalid timestamps are only considered on a per
|
||||||
|
recipe file basis.
|
||||||
|
So, for example, if the configure stamp has a timestamp greater than the
|
||||||
|
compile timestamp for a given target, then the compile task would rerun.
|
||||||
|
Running the compile task again, however, has no effect on other providers
|
||||||
|
that depend on that target.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The exact format of the stamps is partly configurable.
|
||||||
|
In modern versions of BitBake, a hash is appended to the
|
||||||
|
stamp so that if the configuration changes, the stamp becomes
|
||||||
|
invalid and the task is automatically rerun.
|
||||||
|
This hash, or signature used, is governed by the signature policy
|
||||||
|
that is configured (see the
|
||||||
|
"<link linkend='checksums'>Checksums (Signatures)</link>"
|
||||||
|
section for information).
|
||||||
|
It is also possible to append extra metadata to the stamp using
|
||||||
|
the <filename>[stamp-extra-info]</filename> task flag.
|
||||||
|
For example, OpenEmbedded uses this flag to make some tasks machine-specific.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
Some tasks are marked as "nostamp" tasks.
|
||||||
|
No timestamp file is created when these tasks are run.
|
||||||
|
Consequently, "nostamp" tasks are always rerun.
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For more information on tasks, see the
|
||||||
|
"<link linkend='tasks'>Tasks</link>" section.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='executing-tasks'>
|
||||||
|
<title>Executing Tasks</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Tasks can be either a shell task or a Python task.
|
||||||
|
For shell tasks, BitBake writes a shell script to
|
||||||
|
<filename>${</filename><link linkend='var-bb-T'><filename>T</filename></link><filename>}/run.do_taskname.pid</filename>
|
||||||
|
and then executes the script.
|
||||||
|
The generated shell script contains all the exported variables,
|
||||||
|
and the shell functions with all variables expanded.
|
||||||
|
Output from the shell script goes to the file
|
||||||
|
<filename>${T}/log.do_taskname.pid</filename>.
|
||||||
|
Looking at the expanded shell functions in the run file and
|
||||||
|
the output in the log files is a useful debugging technique.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For Python tasks, BitBake executes the task internally and logs
|
||||||
|
information to the controlling terminal.
|
||||||
|
Future versions of BitBake will write the functions to files
|
||||||
|
similar to the way shell tasks are handled.
|
||||||
|
Logging will be handled in a way similar to shell tasks as well.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The order in which BitBake runs the tasks is controlled by its
|
||||||
|
task scheduler.
|
||||||
|
It is possible to configure the scheduler and define custom
|
||||||
|
implementations for specific use cases.
|
||||||
|
For more information, see these variables that control the
|
||||||
|
behavior:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
<link linkend='var-bb-BB_SCHEDULER'><filename>BB_SCHEDULER</filename></link>
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
<link linkend='var-bb-BB_SCHEDULERS'><filename>BB_SCHEDULERS</filename></link>
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
It is possible to have functions run before and after a task's main
|
||||||
|
function.
|
||||||
|
This is done using the <filename>[prefuncs]</filename>
|
||||||
|
and <filename>[postfuncs]</filename> flags of the task
|
||||||
|
that lists the functions to run.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='checksums'>
|
||||||
|
<title>Checksums (Signatures)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A checksum is a unique signature of a task's inputs.
|
||||||
|
The signature of a task can be used to determine if a task
|
||||||
|
needs to be run.
|
||||||
|
Because it is a change in a task's inputs that triggers running
|
||||||
|
the task, BitBake needs to detect all the inputs to a given task.
|
||||||
|
For shell tasks, this turns out to be fairly easy because
|
||||||
|
BitBake generates a "run" shell script for each task and
|
||||||
|
it is possible to create a checksum that gives you a good idea of when
|
||||||
|
the task's data changes.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To complicate the problem, some things should not be included in
|
||||||
|
the checksum.
|
||||||
|
First, there is the actual specific build path of a given task -
|
||||||
|
the working directory.
|
||||||
|
It does not matter if the working directory changes because it should not
|
||||||
|
affect the output for target packages.
|
||||||
|
The simplistic approach for excluding the working directory is to set
|
||||||
|
it to some fixed value and create the checksum for the "run" script.
|
||||||
|
BitBake goes one step better and uses the
|
||||||
|
<link linkend='var-bb-BB_HASHBASE_WHITELIST'><filename>BB_HASHBASE_WHITELIST</filename></link>
|
||||||
|
variable to define a list of variables that should never be included
|
||||||
|
when generating the signatures.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Another problem results from the "run" scripts containing functions that
|
||||||
|
might or might not get called.
|
||||||
|
The incremental build solution contains code that figures out dependencies
|
||||||
|
between shell functions.
|
||||||
|
This code is used to prune the "run" scripts down to the minimum set,
|
||||||
|
thereby alleviating this problem and making the "run" scripts much more
|
||||||
|
readable as a bonus.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
So far we have solutions for shell scripts.
|
||||||
|
What about Python tasks?
|
||||||
|
The same approach applies even though these tasks are more difficult.
|
||||||
|
The process needs to figure out what variables a Python function accesses
|
||||||
|
and what functions it calls.
|
||||||
|
Again, the incremental build solution contains code that first figures out
|
||||||
|
the variable and function dependencies, and then creates a checksum for the data
|
||||||
|
used as the input to the task.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Like the working directory case, situations exist where dependencies
|
||||||
|
should be ignored.
|
||||||
|
For these cases, you can instruct the build process to ignore a dependency
|
||||||
|
by using a line like the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
PACKAGE_ARCHS[vardepsexclude] = "MACHINE"
|
||||||
|
</literallayout>
|
||||||
|
This example ensures that the <filename>PACKAGE_ARCHS</filename> variable does not
|
||||||
|
depend on the value of <filename>MACHINE</filename>, even if it does reference it.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Equally, there are cases where we need to add dependencies BitBake
|
||||||
|
is not able to find.
|
||||||
|
You can accomplish this by using a line like the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
PACKAGE_ARCHS[vardeps] = "MACHINE"
|
||||||
|
</literallayout>
|
||||||
|
This example explicitly adds the <filename>MACHINE</filename> variable as a
|
||||||
|
dependency for <filename>PACKAGE_ARCHS</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Consider a case with in-line Python, for example, where BitBake is not
|
||||||
|
able to figure out dependencies.
|
||||||
|
When running in debug mode (i.e. using <filename>-DDD</filename>), BitBake
|
||||||
|
produces output when it discovers something for which it cannot figure out
|
||||||
|
dependencies.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Thus far, this section has limited discussion to the direct inputs into a task.
|
||||||
|
Information based on direct inputs is referred to as the "basehash" in the
|
||||||
|
code.
|
||||||
|
However, there is still the question of a task's indirect inputs - the
|
||||||
|
things that were already built and present in the build directory.
|
||||||
|
The checksum (or signature) for a particular task needs to add the hashes
|
||||||
|
of all the tasks on which the particular task depends.
|
||||||
|
Choosing which dependencies to add is a policy decision.
|
||||||
|
However, the effect is to generate a master checksum that combines the basehash
|
||||||
|
and the hashes of the task's dependencies.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
At the code level, there are a variety of ways both the basehash and the
|
||||||
|
dependent task hashes can be influenced.
|
||||||
|
Within the BitBake configuration file, we can give BitBake some extra information
|
||||||
|
to help it construct the basehash.
|
||||||
|
The following statement effectively results in a list of global variable
|
||||||
|
dependency excludes - variables never included in any checksum.
|
||||||
|
This example uses variables from OpenEmbedded to help illustrate
|
||||||
|
the concept:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
BB_HASHBASE_WHITELIST ?= "TMPDIR FILE PATH PWD BB_TASKHASH BBPATH DL_DIR \
|
||||||
|
SSTATE_DIR THISDIR FILESEXTRAPATHS FILE_DIRNAME HOME LOGNAME SHELL TERM \
|
||||||
|
USER FILESPATH STAGING_DIR_HOST STAGING_DIR_TARGET COREBASE PRSERV_HOST \
|
||||||
|
PRSERV_DUMPDIR PRSERV_DUMPFILE PRSERV_LOCKDOWN PARALLEL_MAKE \
|
||||||
|
CCACHE_DIR EXTERNAL_TOOLCHAIN CCACHE CCACHE_DISABLE LICENSE_PATH SDKPKGSUFFIX"
|
||||||
|
</literallayout>
|
||||||
|
The previous example excludes the work directory, which is part of
|
||||||
|
<filename>TMPDIR</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The rules for deciding which hashes of dependent tasks to include through
|
||||||
|
dependency chains are more complex and are generally accomplished with a
|
||||||
|
Python function.
|
||||||
|
The code in <filename>meta/lib/oe/sstatesig.py</filename> shows two examples
|
||||||
|
of this and also illustrates how you can insert your own policy into the system
|
||||||
|
if so desired.
|
||||||
|
This file defines the two basic signature generators OpenEmbedded-Core
|
||||||
|
uses: "OEBasic" and "OEBasicHash".
|
||||||
|
By default, there is a dummy "noop" signature handler enabled in BitBake.
|
||||||
|
This means that behavior is unchanged from previous versions.
|
||||||
|
<filename>OE-Core</filename> uses the "OEBasicHash" signature handler by default
|
||||||
|
through this setting in the <filename>bitbake.conf</filename> file:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
BB_SIGNATURE_HANDLER ?= "OEBasicHash"
|
||||||
|
</literallayout>
|
||||||
|
The "OEBasicHash" <filename>BB_SIGNATURE_HANDLER</filename> is the same as the
|
||||||
|
"OEBasic" version but adds the task hash to the stamp files.
|
||||||
|
This results in any metadata change that changes the task hash, automatically
|
||||||
|
causing the task to be run again.
|
||||||
|
This removes the need to bump
|
||||||
|
<link linkend='var-bb-PR'><filename>PR</filename></link>
|
||||||
|
values, and changes to metadata automatically ripple across the build.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
It is also worth noting that the end result of these signature generators is to
|
||||||
|
make some dependency and hash information available to the build.
|
||||||
|
This information includes:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><filename>BB_BASEHASH_task-</filename><replaceable>taskname</replaceable>:
|
||||||
|
The base hashes for each task in the recipe.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>BB_BASEHASH_</filename><replaceable>filename</replaceable><filename>:</filename><replaceable>taskname</replaceable>:
|
||||||
|
The base hashes for each dependent task.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>BBHASHDEPS_</filename><replaceable>filename</replaceable><filename>:</filename><replaceable>taskname</replaceable>:
|
||||||
|
The task dependencies for each task.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>BB_TASKHASH</filename>:
|
||||||
|
The hash of the currently running task.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
It is worth noting that BitBake's "-S" option lets you
|
||||||
|
debug Bitbake's processing of signatures.
|
||||||
|
The options passed to -S allow different debugging modes
|
||||||
|
to be used, either using BitBake's own debug functions
|
||||||
|
or possibly those defined in the metadata/signature handler
|
||||||
|
itself.
|
||||||
|
The simplest parameter to pass is "none", which causes a
|
||||||
|
set of signature information to be written out into
|
||||||
|
<filename>STAMPS_DIR</filename>
|
||||||
|
corresponding to the targets specified.
|
||||||
|
The other currently available parameter is "printdiff",
|
||||||
|
which causes BitBake to try to establish the closest
|
||||||
|
signature match it can (e.g. in the sstate cache) and then
|
||||||
|
run <filename>bitbake-diffsigs</filename> over the matches
|
||||||
|
to determine the stamps and delta where these two
|
||||||
|
stamp trees diverge.
|
||||||
|
<note>
|
||||||
|
It is likely that future versions of BitBake will
|
||||||
|
provide other signature handlers triggered through
|
||||||
|
additional "-S" parameters.
|
||||||
|
</note>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
You can find more information on checksum metadata in the
|
||||||
|
"<link linkend='task-checksums-and-setscene'>Task Checksums and Setscene</link>"
|
||||||
|
section.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='setscene'>
|
||||||
|
<title>Setscene</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The setscene process enables BitBake to handle "pre-built" artifacts.
|
||||||
|
The ability to handle and reuse these artifacts allows BitBake
|
||||||
|
the luxury of not having to build something from scratch every time.
|
||||||
|
Instead, BitBake can use, when possible, existing build artifacts.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake needs to have reliable data indicating whether or not an
|
||||||
|
artifact is compatible.
|
||||||
|
Signatures, described in the previous section, provide an ideal
|
||||||
|
way of representing whether an artifact is compatible.
|
||||||
|
If a signature is the same, an object can be reused.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If an object can be reused, the problem then becomes how to
|
||||||
|
replace a given task or set of tasks with the pre-built artifact.
|
||||||
|
BitBake solves the problem with the "setscene" process.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When BitBake is asked to build a given target, before building anything,
|
||||||
|
it first asks whether cached information is available for any of the
|
||||||
|
targets it's building, or any of the intermediate targets.
|
||||||
|
If cached information is available, BitBake uses this information instead of
|
||||||
|
running the main tasks.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake first calls the function defined by the
|
||||||
|
<link linkend='var-bb-BB_HASHCHECK_FUNCTION'><filename>BB_HASHCHECK_FUNCTION</filename></link>
|
||||||
|
variable with a list of tasks and corresponding
|
||||||
|
hashes it wants to build.
|
||||||
|
This function is designed to be fast and returns a list
|
||||||
|
of the tasks for which it believes in can obtain artifacts.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Next, for each of the tasks that were returned as possibilities,
|
||||||
|
BitBake executes a setscene version of the task that the possible
|
||||||
|
artifact covers.
|
||||||
|
Setscene versions of a task have the string "_setscene" appended to the
|
||||||
|
task name.
|
||||||
|
So, for example, the task with the name <filename>xxx</filename> has
|
||||||
|
a setscene task named <filename>xxx_setscene</filename>.
|
||||||
|
The setscene version of the task executes and provides the necessary
|
||||||
|
artifacts returning either success or failure.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As previously mentioned, an artifact can cover more than one task.
|
||||||
|
For example, it is pointless to obtain a compiler if you
|
||||||
|
already have the compiled binary.
|
||||||
|
To handle this, BitBake calls the
|
||||||
|
<link linkend='var-bb-BB_SETSCENE_DEPVALID'><filename>BB_SETSCENE_DEPVALID</filename></link>
|
||||||
|
function for each successful setscene task to know whether or not it needs
|
||||||
|
to obtain the dependencies of that task.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Finally, after all the setscene tasks have executed, BitBake calls the
|
||||||
|
function listed in
|
||||||
|
<link linkend='var-bb-BB_SETSCENE_VERIFY_FUNCTION2'><filename>BB_SETSCENE_VERIFY_FUNCTION2</filename></link>
|
||||||
|
with the list of tasks BitBake thinks has been "covered".
|
||||||
|
The metadata can then ensure that this list is correct and can
|
||||||
|
inform BitBake that it wants specific tasks to be run regardless
|
||||||
|
of the setscene result.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
You can find more information on setscene metadata in the
|
||||||
|
"<link linkend='task-checksums-and-setscene'>Task Checksums and Setscene</link>"
|
||||||
|
section.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</chapter>
|
||||||
@@ -1,851 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: CC-BY-2.5
|
|
||||||
|
|
||||||
=====================
|
|
||||||
File Download Support
|
|
||||||
=====================
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
BitBake's fetch module is a standalone piece of library code that deals
|
|
||||||
with the intricacies of downloading source code and files from remote
|
|
||||||
systems. Fetching source code is one of the cornerstones of building
|
|
||||||
software. As such, this module forms an important part of BitBake.
|
|
||||||
|
|
||||||
The current fetch module is called "fetch2" and refers to the fact that
|
|
||||||
it is the second major version of the API. The original version is
|
|
||||||
obsolete and has been removed from the codebase. Thus, in all cases,
|
|
||||||
"fetch" refers to "fetch2" in this manual.
|
|
||||||
|
|
||||||
The Download (Fetch)
|
|
||||||
====================
|
|
||||||
|
|
||||||
BitBake takes several steps when fetching source code or files. The
|
|
||||||
fetcher codebase deals with two distinct processes in order: obtaining
|
|
||||||
the files from somewhere (cached or otherwise) and then unpacking those
|
|
||||||
files into a specific location and perhaps in a specific way. Getting
|
|
||||||
and unpacking the files is often optionally followed by patching.
|
|
||||||
Patching, however, is not covered by this module.
|
|
||||||
|
|
||||||
The code to execute the first part of this process, a fetch, looks
|
|
||||||
something like the following::
|
|
||||||
|
|
||||||
src_uri = (d.getVar('SRC_URI') or "").split()
|
|
||||||
fetcher = bb.fetch2.Fetch(src_uri, d)
|
|
||||||
fetcher.download()
|
|
||||||
|
|
||||||
This code sets up an instance of the fetch class. The instance uses a
|
|
||||||
space-separated list of URLs from the :term:`SRC_URI`
|
|
||||||
variable and then calls the ``download`` method to download the files.
|
|
||||||
|
|
||||||
The instantiation of the fetch class is usually followed by::
|
|
||||||
|
|
||||||
rootdir = l.getVar('WORKDIR')
|
|
||||||
fetcher.unpack(rootdir)
|
|
||||||
|
|
||||||
This code unpacks the downloaded files to the specified by ``WORKDIR``.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
For convenience, the naming in these examples matches the variables
|
|
||||||
used by OpenEmbedded. If you want to see the above code in action,
|
|
||||||
examine the OpenEmbedded class file ``base.bbclass``
|
|
||||||
.
|
|
||||||
|
|
||||||
The :term:`SRC_URI` and ``WORKDIR`` variables are not hardcoded into the
|
|
||||||
fetcher, since those fetcher methods can be (and are) called with
|
|
||||||
different variable names. In OpenEmbedded for example, the shared state
|
|
||||||
(sstate) code uses the fetch module to fetch the sstate files.
|
|
||||||
|
|
||||||
When the ``download()`` method is called, BitBake tries to resolve the
|
|
||||||
URLs by looking for source files in a specific search order:
|
|
||||||
|
|
||||||
- *Pre-mirror Sites:* BitBake first uses pre-mirrors to try and find
|
|
||||||
source files. These locations are defined using the
|
|
||||||
:term:`PREMIRRORS` variable.
|
|
||||||
|
|
||||||
- *Source URI:* If pre-mirrors fail, BitBake uses the original URL (e.g
|
|
||||||
from :term:`SRC_URI`).
|
|
||||||
|
|
||||||
- *Mirror Sites:* If fetch failures occur, BitBake next uses mirror
|
|
||||||
locations as defined by the :term:`MIRRORS` variable.
|
|
||||||
|
|
||||||
For each URL passed to the fetcher, the fetcher calls the submodule that
|
|
||||||
handles that particular URL type. This behavior can be the source of
|
|
||||||
some confusion when you are providing URLs for the :term:`SRC_URI` variable.
|
|
||||||
Consider the following two URLs::
|
|
||||||
|
|
||||||
https://git.yoctoproject.org/git/poky;protocol=git
|
|
||||||
git://git.yoctoproject.org/git/poky;protocol=http
|
|
||||||
|
|
||||||
In the former case, the URL is passed to the ``wget`` fetcher, which does not
|
|
||||||
understand "git". Therefore, the latter case is the correct form since the Git
|
|
||||||
fetcher does know how to use HTTP as a transport.
|
|
||||||
|
|
||||||
Here are some examples that show commonly used mirror definitions::
|
|
||||||
|
|
||||||
PREMIRRORS ?= "\
|
|
||||||
bzr://.*/.\* http://somemirror.org/sources/ \
|
|
||||||
cvs://.*/.\* http://somemirror.org/sources/ \
|
|
||||||
git://.*/.\* http://somemirror.org/sources/ \
|
|
||||||
hg://.*/.\* http://somemirror.org/sources/ \
|
|
||||||
osc://.*/.\* http://somemirror.org/sources/ \
|
|
||||||
p4://.*/.\* http://somemirror.org/sources/ \
|
|
||||||
svn://.*/.\* http://somemirror.org/sources/"
|
|
||||||
|
|
||||||
MIRRORS =+ "\
|
|
||||||
ftp://.*/.\* http://somemirror.org/sources/ \
|
|
||||||
http://.*/.\* http://somemirror.org/sources/ \
|
|
||||||
https://.*/.\* http://somemirror.org/sources/"
|
|
||||||
|
|
||||||
It is useful to note that BitBake
|
|
||||||
supports cross-URLs. It is possible to mirror a Git repository on an
|
|
||||||
HTTP server as a tarball. This is what the ``git://`` mapping in the
|
|
||||||
previous example does.
|
|
||||||
|
|
||||||
Since network accesses are slow, BitBake maintains a cache of files
|
|
||||||
downloaded from the network. Any source files that are not local (i.e.
|
|
||||||
downloaded from the Internet) are placed into the download directory,
|
|
||||||
which is specified by the :term:`DL_DIR` variable.
|
|
||||||
|
|
||||||
File integrity is of key importance for reproducing builds. For
|
|
||||||
non-local archive downloads, the fetcher code can verify SHA-256 and MD5
|
|
||||||
checksums to ensure the archives have been downloaded correctly. You can
|
|
||||||
specify these checksums by using the :term:`SRC_URI` variable with the
|
|
||||||
appropriate varflags as follows::
|
|
||||||
|
|
||||||
SRC_URI[md5sum] = "value"
|
|
||||||
SRC_URI[sha256sum] = "value"
|
|
||||||
|
|
||||||
You can also specify the checksums as
|
|
||||||
parameters on the :term:`SRC_URI` as shown below::
|
|
||||||
|
|
||||||
SRC_URI = "http://example.com/foobar.tar.bz2;md5sum=4a8e0f237e961fd7785d19d07fdb994d"
|
|
||||||
|
|
||||||
If multiple URIs exist, you can specify the checksums either directly as
|
|
||||||
in the previous example, or you can name the URLs. The following syntax
|
|
||||||
shows how you name the URIs::
|
|
||||||
|
|
||||||
SRC_URI = "http://example.com/foobar.tar.bz2;name=foo"
|
|
||||||
SRC_URI[foo.md5sum] = 4a8e0f237e961fd7785d19d07fdb994d
|
|
||||||
|
|
||||||
After a file has been downloaded and
|
|
||||||
has had its checksum checked, a ".done" stamp is placed in :term:`DL_DIR`.
|
|
||||||
BitBake uses this stamp during subsequent builds to avoid downloading or
|
|
||||||
comparing a checksum for the file again.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
It is assumed that local storage is safe from data corruption. If
|
|
||||||
this were not the case, there would be bigger issues to worry about.
|
|
||||||
|
|
||||||
If :term:`BB_STRICT_CHECKSUM` is set, any
|
|
||||||
download without a checksum triggers an error message. The
|
|
||||||
:term:`BB_NO_NETWORK` variable can be used to
|
|
||||||
make any attempted network access a fatal error, which is useful for
|
|
||||||
checking that mirrors are complete as well as other things.
|
|
||||||
|
|
||||||
If :term:`BB_CHECK_SSL_CERTS` is set to ``0`` then SSL certificate checking will
|
|
||||||
be disabled. This variable defaults to ``1`` so SSL certificates are normally
|
|
||||||
checked.
|
|
||||||
|
|
||||||
.. _bb-the-unpack:
|
|
||||||
|
|
||||||
The Unpack
|
|
||||||
==========
|
|
||||||
|
|
||||||
The unpack process usually immediately follows the download. For all
|
|
||||||
URLs except Git URLs, BitBake uses the common ``unpack`` method.
|
|
||||||
|
|
||||||
A number of parameters exist that you can specify within the URL to
|
|
||||||
govern the behavior of the unpack stage:
|
|
||||||
|
|
||||||
- *unpack:* Controls whether the URL components are unpacked. If set to
|
|
||||||
"1", which is the default, the components are unpacked. If set to
|
|
||||||
"0", the unpack stage leaves the file alone. This parameter is useful
|
|
||||||
when you want an archive to be copied in and not be unpacked.
|
|
||||||
|
|
||||||
- *dos:* Applies to ``.zip`` and ``.jar`` files and specifies whether
|
|
||||||
to use DOS line ending conversion on text files.
|
|
||||||
|
|
||||||
- *striplevel:* Strip specified number of leading components (levels)
|
|
||||||
from file names on extraction
|
|
||||||
|
|
||||||
- *subdir:* Unpacks the specific URL to the specified subdirectory
|
|
||||||
within the root directory.
|
|
||||||
|
|
||||||
The unpack call automatically decompresses and extracts files with ".Z",
|
|
||||||
".z", ".gz", ".xz", ".zip", ".jar", ".ipk", ".rpm". ".srpm", ".deb" and
|
|
||||||
".bz2" extensions as well as various combinations of tarball extensions.
|
|
||||||
|
|
||||||
As mentioned, the Git fetcher has its own unpack method that is
|
|
||||||
optimized to work with Git trees. Basically, this method works by
|
|
||||||
cloning the tree into the final directory. The process is completed
|
|
||||||
using references so that there is only one central copy of the Git
|
|
||||||
metadata needed.
|
|
||||||
|
|
||||||
.. _bb-fetchers:
|
|
||||||
|
|
||||||
Fetchers
|
|
||||||
========
|
|
||||||
|
|
||||||
As mentioned earlier, the URL prefix determines which fetcher submodule
|
|
||||||
BitBake uses. Each submodule can support different URL parameters, which
|
|
||||||
are described in the following sections.
|
|
||||||
|
|
||||||
.. _local-file-fetcher:
|
|
||||||
|
|
||||||
Local file fetcher (``file://``)
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
This submodule handles URLs that begin with ``file://``. The filename
|
|
||||||
you specify within the URL can be either an absolute or relative path to
|
|
||||||
a file. If the filename is relative, the contents of the
|
|
||||||
:term:`FILESPATH` variable is used in the same way
|
|
||||||
``PATH`` is used to find executables. If the file cannot be found, it is
|
|
||||||
assumed that it is available in :term:`DL_DIR` by the
|
|
||||||
time the ``download()`` method is called.
|
|
||||||
|
|
||||||
If you specify a directory, the entire directory is unpacked.
|
|
||||||
|
|
||||||
Here are a couple of example URLs, the first relative and the second
|
|
||||||
absolute::
|
|
||||||
|
|
||||||
SRC_URI = "file://relativefile.patch"
|
|
||||||
SRC_URI = "file:///Users/ich/very_important_software"
|
|
||||||
|
|
||||||
.. _http-ftp-fetcher:
|
|
||||||
|
|
||||||
HTTP/FTP wget fetcher (``http://``, ``ftp://``, ``https://``)
|
|
||||||
-------------------------------------------------------------
|
|
||||||
|
|
||||||
This fetcher obtains files from web and FTP servers. Internally, the
|
|
||||||
fetcher uses the wget utility.
|
|
||||||
|
|
||||||
The executable and parameters used are specified by the
|
|
||||||
``FETCHCMD_wget`` variable, which defaults to sensible values. The
|
|
||||||
fetcher supports a parameter "downloadfilename" that allows the name of
|
|
||||||
the downloaded file to be specified. Specifying the name of the
|
|
||||||
downloaded file is useful for avoiding collisions in
|
|
||||||
:term:`DL_DIR` when dealing with multiple files that
|
|
||||||
have the same name.
|
|
||||||
|
|
||||||
If a username and password are specified in the ``SRC_URI``, a Basic
|
|
||||||
Authorization header will be added to each request, including across redirects.
|
|
||||||
To instead limit the Authorization header to the first request, add
|
|
||||||
"redirectauth=0" to the list of parameters.
|
|
||||||
|
|
||||||
Some example URLs are as follows::
|
|
||||||
|
|
||||||
SRC_URI = "http://oe.handhelds.org/not_there.aac"
|
|
||||||
SRC_URI = "ftp://oe.handhelds.org/not_there_as_well.aac"
|
|
||||||
SRC_URI = "ftp://you@oe.handhelds.org/home/you/secret.plan"
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Because URL parameters are delimited by semi-colons, this can
|
|
||||||
introduce ambiguity when parsing URLs that also contain semi-colons,
|
|
||||||
for example::
|
|
||||||
|
|
||||||
SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git;a=snapshot;h=a5dd47"
|
|
||||||
|
|
||||||
|
|
||||||
Such URLs should should be modified by replacing semi-colons with '&'
|
|
||||||
characters::
|
|
||||||
|
|
||||||
SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git&a=snapshot&h=a5dd47"
|
|
||||||
|
|
||||||
|
|
||||||
In most cases this should work. Treating semi-colons and '&' in
|
|
||||||
queries identically is recommended by the World Wide Web Consortium
|
|
||||||
(W3C). Note that due to the nature of the URL, you may have to
|
|
||||||
specify the name of the downloaded file as well::
|
|
||||||
|
|
||||||
SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git&a=snapshot&h=a5dd47;downloadfilename=myfile.bz2"
|
|
||||||
|
|
||||||
|
|
||||||
.. _cvs-fetcher:
|
|
||||||
|
|
||||||
CVS fetcher (``(cvs://``)
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
This submodule handles checking out files from the CVS version control
|
|
||||||
system. You can configure it using a number of different variables:
|
|
||||||
|
|
||||||
- :term:`FETCHCMD_cvs <FETCHCMD>`: The name of the executable to use when running
|
|
||||||
the ``cvs`` command. This name is usually "cvs".
|
|
||||||
|
|
||||||
- :term:`SRCDATE`: The date to use when fetching the CVS source code. A
|
|
||||||
special value of "now" causes the checkout to be updated on every
|
|
||||||
build.
|
|
||||||
|
|
||||||
- :term:`CVSDIR`: Specifies where a temporary
|
|
||||||
checkout is saved. The location is often ``DL_DIR/cvs``.
|
|
||||||
|
|
||||||
- CVS_PROXY_HOST: The name to use as a "proxy=" parameter to the
|
|
||||||
``cvs`` command.
|
|
||||||
|
|
||||||
- CVS_PROXY_PORT: The port number to use as a "proxyport="
|
|
||||||
parameter to the ``cvs`` command.
|
|
||||||
|
|
||||||
As well as the standard username and password URL syntax, you can also
|
|
||||||
configure the fetcher with various URL parameters:
|
|
||||||
|
|
||||||
The supported parameters are as follows:
|
|
||||||
|
|
||||||
- *"method":* The protocol over which to communicate with the CVS
|
|
||||||
server. By default, this protocol is "pserver". If "method" is set to
|
|
||||||
"ext", BitBake examines the "rsh" parameter and sets ``CVS_RSH``. You
|
|
||||||
can use "dir" for local directories.
|
|
||||||
|
|
||||||
- *"module":* Specifies the module to check out. You must supply this
|
|
||||||
parameter.
|
|
||||||
|
|
||||||
- *"tag":* Describes which CVS TAG should be used for the checkout. By
|
|
||||||
default, the TAG is empty.
|
|
||||||
|
|
||||||
- *"date":* Specifies a date. If no "date" is specified, the
|
|
||||||
:term:`SRCDATE` of the configuration is used to
|
|
||||||
checkout a specific date. The special value of "now" causes the
|
|
||||||
checkout to be updated on every build.
|
|
||||||
|
|
||||||
- *"localdir":* Used to rename the module. Effectively, you are
|
|
||||||
renaming the output directory to which the module is unpacked. You
|
|
||||||
are forcing the module into a special directory relative to
|
|
||||||
:term:`CVSDIR`.
|
|
||||||
|
|
||||||
- *"rsh":* Used in conjunction with the "method" parameter.
|
|
||||||
|
|
||||||
- *"scmdata":* Causes the CVS metadata to be maintained in the tarball
|
|
||||||
the fetcher creates when set to "keep". The tarball is expanded into
|
|
||||||
the work directory. By default, the CVS metadata is removed.
|
|
||||||
|
|
||||||
- *"fullpath":* Controls whether the resulting checkout is at the
|
|
||||||
module level, which is the default, or is at deeper paths.
|
|
||||||
|
|
||||||
- *"norecurse":* Causes the fetcher to only checkout the specified
|
|
||||||
directory with no recurse into any subdirectories.
|
|
||||||
|
|
||||||
- *"port":* The port to which the CVS server connects.
|
|
||||||
|
|
||||||
Some example URLs are as follows::
|
|
||||||
|
|
||||||
SRC_URI = "cvs://CVSROOT;module=mymodule;tag=some-version;method=ext"
|
|
||||||
SRC_URI = "cvs://CVSROOT;module=mymodule;date=20060126;localdir=usethat"
|
|
||||||
|
|
||||||
.. _svn-fetcher:
|
|
||||||
|
|
||||||
Subversion (SVN) Fetcher (``svn://``)
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
This fetcher submodule fetches code from the Subversion source control
|
|
||||||
system. The executable used is specified by ``FETCHCMD_svn``, which
|
|
||||||
defaults to "svn". The fetcher's temporary working directory is set by
|
|
||||||
:term:`SVNDIR`, which is usually ``DL_DIR/svn``.
|
|
||||||
|
|
||||||
The supported parameters are as follows:
|
|
||||||
|
|
||||||
- *"module":* The name of the svn module to checkout. You must provide
|
|
||||||
this parameter. You can think of this parameter as the top-level
|
|
||||||
directory of the repository data you want.
|
|
||||||
|
|
||||||
- *"path_spec":* A specific directory in which to checkout the
|
|
||||||
specified svn module.
|
|
||||||
|
|
||||||
- *"protocol":* The protocol to use, which defaults to "svn". If
|
|
||||||
"protocol" is set to "svn+ssh", the "ssh" parameter is also used.
|
|
||||||
|
|
||||||
- *"rev":* The revision of the source code to checkout.
|
|
||||||
|
|
||||||
- *"scmdata":* Causes the ".svn" directories to be available during
|
|
||||||
compile-time when set to "keep". By default, these directories are
|
|
||||||
removed.
|
|
||||||
|
|
||||||
- *"ssh":* An optional parameter used when "protocol" is set to
|
|
||||||
"svn+ssh". You can use this parameter to specify the ssh program used
|
|
||||||
by svn.
|
|
||||||
|
|
||||||
- *"transportuser":* When required, sets the username for the
|
|
||||||
transport. By default, this parameter is empty. The transport
|
|
||||||
username is different than the username used in the main URL, which
|
|
||||||
is passed to the subversion command.
|
|
||||||
|
|
||||||
Following are three examples using svn::
|
|
||||||
|
|
||||||
SRC_URI = "svn://myrepos/proj1;module=vip;protocol=http;rev=667"
|
|
||||||
SRC_URI = "svn://myrepos/proj1;module=opie;protocol=svn+ssh"
|
|
||||||
SRC_URI = "svn://myrepos/proj1;module=trunk;protocol=http;path_spec=${MY_DIR}/proj1"
|
|
||||||
|
|
||||||
.. _git-fetcher:
|
|
||||||
|
|
||||||
Git Fetcher (``git://``)
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
This fetcher submodule fetches code from the Git source control system.
|
|
||||||
The fetcher works by creating a bare clone of the remote into
|
|
||||||
:term:`GITDIR`, which is usually ``DL_DIR/git2``. This
|
|
||||||
bare clone is then cloned into the work directory during the unpack
|
|
||||||
stage when a specific tree is checked out. This is done using alternates
|
|
||||||
and by reference to minimize the amount of duplicate data on the disk
|
|
||||||
and make the unpack process fast. The executable used can be set with
|
|
||||||
``FETCHCMD_git``.
|
|
||||||
|
|
||||||
This fetcher supports the following parameters:
|
|
||||||
|
|
||||||
- *"protocol":* The protocol used to fetch the files. The default is
|
|
||||||
"git" when a hostname is set. If a hostname is not set, the Git
|
|
||||||
protocol is "file". You can also use "http", "https", "ssh" and
|
|
||||||
"rsync".
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
When ``protocol`` is "ssh", the URL expected in :term:`SRC_URI` differs
|
|
||||||
from the one that is typically passed to ``git clone`` command and provided
|
|
||||||
by the Git server to fetch from. For example, the URL returned by GitLab
|
|
||||||
server for ``mesa`` when cloning over SSH is
|
|
||||||
``git@gitlab.freedesktop.org:mesa/mesa.git``, however the expected URL in
|
|
||||||
:term:`SRC_URI` is the following::
|
|
||||||
|
|
||||||
SRC_URI = "git://git@gitlab.freedesktop.org/mesa/mesa.git;branch=main;protocol=ssh;..."
|
|
||||||
|
|
||||||
Note the ``:`` character changed for a ``/`` before the path to the project.
|
|
||||||
|
|
||||||
- *"nocheckout":* Tells the fetcher to not checkout source code when
|
|
||||||
unpacking when set to "1". Set this option for the URL where there is
|
|
||||||
a custom routine to checkout code. The default is "0".
|
|
||||||
|
|
||||||
- *"rebaseable":* Indicates that the upstream Git repository can be
|
|
||||||
rebased. You should set this parameter to "1" if revisions can become
|
|
||||||
detached from branches. In this case, the source mirror tarball is
|
|
||||||
done per revision, which has a loss of efficiency. Rebasing the
|
|
||||||
upstream Git repository could cause the current revision to disappear
|
|
||||||
from the upstream repository. This option reminds the fetcher to
|
|
||||||
preserve the local cache carefully for future use. The default value
|
|
||||||
for this parameter is "0".
|
|
||||||
|
|
||||||
- *"nobranch":* Tells the fetcher to not check the SHA validation for
|
|
||||||
the branch when set to "1". The default is "0". Set this option for
|
|
||||||
the recipe that refers to the commit that is valid for any namespace
|
|
||||||
(branch, tag, ...) instead of the branch.
|
|
||||||
|
|
||||||
- *"bareclone":* Tells the fetcher to clone a bare clone into the
|
|
||||||
destination directory without checking out a working tree. Only the
|
|
||||||
raw Git metadata is provided. This parameter implies the "nocheckout"
|
|
||||||
parameter as well.
|
|
||||||
|
|
||||||
- *"branch":* The branch(es) of the Git tree to clone. Unless
|
|
||||||
"nobranch" is set to "1", this is a mandatory parameter. The number of
|
|
||||||
branch parameters must match the number of name parameters.
|
|
||||||
|
|
||||||
- *"rev":* The revision to use for the checkout. The default is
|
|
||||||
"master".
|
|
||||||
|
|
||||||
- *"tag":* Specifies a tag to use for the checkout. To correctly
|
|
||||||
resolve tags, BitBake must access the network. For that reason, tags
|
|
||||||
are often not used. As far as Git is concerned, the "tag" parameter
|
|
||||||
behaves effectively the same as the "rev" parameter.
|
|
||||||
|
|
||||||
- *"subpath":* Limits the checkout to a specific subpath of the tree.
|
|
||||||
By default, the whole tree is checked out.
|
|
||||||
|
|
||||||
- *"destsuffix":* The name of the path in which to place the checkout.
|
|
||||||
By default, the path is ``git/``.
|
|
||||||
|
|
||||||
- *"usehead":* Enables local ``git://`` URLs to use the current branch
|
|
||||||
HEAD as the revision for use with ``AUTOREV``. The "usehead"
|
|
||||||
parameter implies no branch and only works when the transfer protocol
|
|
||||||
is ``file://``.
|
|
||||||
|
|
||||||
Here are some example URLs::
|
|
||||||
|
|
||||||
SRC_URI = "git://github.com/fronteed/icheck.git;protocol=https;branch=${PV};tag=${PV}"
|
|
||||||
SRC_URI = "git://github.com/asciidoc/asciidoc-py;protocol=https;branch=main"
|
|
||||||
SRC_URI = "git://git@gitlab.freedesktop.org/mesa/mesa.git;branch=main;protocol=ssh;..."
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
When using ``git`` as the fetcher of the main source code of your software,
|
|
||||||
``S`` should be set accordingly::
|
|
||||||
|
|
||||||
S = "${WORKDIR}/git"
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Specifying passwords directly in ``git://`` urls is not supported.
|
|
||||||
There are several reasons: :term:`SRC_URI` is often written out to logs and
|
|
||||||
other places, and that could easily leak passwords; it is also all too
|
|
||||||
easy to share metadata without removing passwords. SSH keys, ``~/.netrc``
|
|
||||||
and ``~/.ssh/config`` files can be used as alternatives.
|
|
||||||
|
|
||||||
Using tags with the git fetcher may cause surprising behaviour. Bitbake needs to
|
|
||||||
resolve the tag to a specific revision and to do that, it has to connect to and use
|
|
||||||
the upstream repository. This is because the revision the tags point at can change and
|
|
||||||
we've seen cases of this happening in well known public repositories. This can mean
|
|
||||||
many more network connections than expected and recipes may be reparsed at every build.
|
|
||||||
Source mirrors will also be bypassed as the upstream repository is the only source
|
|
||||||
of truth to resolve the revision accurately. For these reasons, whilst the fetcher
|
|
||||||
can support tags, we recommend being specific about revisions in recipes.
|
|
||||||
|
|
||||||
.. _gitsm-fetcher:
|
|
||||||
|
|
||||||
Git Submodule Fetcher (``gitsm://``)
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
This fetcher submodule inherits from the :ref:`Git
|
|
||||||
fetcher<bitbake-user-manual/bitbake-user-manual-fetching:git fetcher
|
|
||||||
(\`\`git://\`\`)>` and extends that fetcher's behavior by fetching a
|
|
||||||
repository's submodules. :term:`SRC_URI` is passed to the Git fetcher as
|
|
||||||
described in the :ref:`bitbake-user-manual/bitbake-user-manual-fetching:git
|
|
||||||
fetcher (\`\`git://\`\`)` section.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
You must clean a recipe when switching between '``git://``' and
|
|
||||||
'``gitsm://``' URLs.
|
|
||||||
|
|
||||||
The Git Submodules fetcher is not a complete fetcher implementation.
|
|
||||||
The fetcher has known issues where it does not use the normal source
|
|
||||||
mirroring infrastructure properly. Further, the submodule sources it
|
|
||||||
fetches are not visible to the licensing and source archiving
|
|
||||||
infrastructures.
|
|
||||||
|
|
||||||
.. _clearcase-fetcher:
|
|
||||||
|
|
||||||
ClearCase Fetcher (``ccrc://``)
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
This fetcher submodule fetches code from a
|
|
||||||
`ClearCase <http://en.wikipedia.org/wiki/Rational_ClearCase>`__
|
|
||||||
repository.
|
|
||||||
|
|
||||||
To use this fetcher, make sure your recipe has proper
|
|
||||||
:term:`SRC_URI`, :term:`SRCREV`, and
|
|
||||||
:term:`PV` settings. Here is an example::
|
|
||||||
|
|
||||||
SRC_URI = "ccrc://cc.example.org/ccrc;vob=/example_vob;module=/example_module"
|
|
||||||
SRCREV = "EXAMPLE_CLEARCASE_TAG"
|
|
||||||
PV = "${@d.getVar("SRCREV", False).replace("/", "+")}"
|
|
||||||
|
|
||||||
The fetcher uses the ``rcleartool`` or
|
|
||||||
``cleartool`` remote client, depending on which one is available.
|
|
||||||
|
|
||||||
Following are options for the :term:`SRC_URI` statement:
|
|
||||||
|
|
||||||
- *vob*: The name, which must include the prepending "/" character,
|
|
||||||
of the ClearCase VOB. This option is required.
|
|
||||||
|
|
||||||
- *module*: The module, which must include the prepending "/"
|
|
||||||
character, in the selected VOB.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
The module and vob options are combined to create the load rule in the
|
|
||||||
view config spec. As an example, consider the vob and module values from
|
|
||||||
the SRC_URI statement at the start of this section. Combining those values
|
|
||||||
results in the following::
|
|
||||||
|
|
||||||
load /example_vob/example_module
|
|
||||||
|
|
||||||
- *proto*: The protocol, which can be either ``http`` or ``https``.
|
|
||||||
|
|
||||||
By default, the fetcher creates a configuration specification. If you
|
|
||||||
want this specification written to an area other than the default, use
|
|
||||||
the ``CCASE_CUSTOM_CONFIG_SPEC`` variable in your recipe to define where
|
|
||||||
the specification is written.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
the SRCREV loses its functionality if you specify this variable. However,
|
|
||||||
SRCREV is still used to label the archive after a fetch even though it does
|
|
||||||
not define what is fetched.
|
|
||||||
|
|
||||||
Here are a couple of other behaviors worth mentioning:
|
|
||||||
|
|
||||||
- When using ``cleartool``, the login of ``cleartool`` is handled by
|
|
||||||
the system. The login require no special steps.
|
|
||||||
|
|
||||||
- In order to use ``rcleartool`` with authenticated users, an
|
|
||||||
"rcleartool login" is necessary before using the fetcher.
|
|
||||||
|
|
||||||
.. _perforce-fetcher:
|
|
||||||
|
|
||||||
Perforce Fetcher (``p4://``)
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
This fetcher submodule fetches code from the
|
|
||||||
`Perforce <https://www.perforce.com/>`__ source control system. The
|
|
||||||
executable used is specified by ``FETCHCMD_p4``, which defaults to "p4".
|
|
||||||
The fetcher's temporary working directory is set by
|
|
||||||
:term:`P4DIR`, which defaults to "DL_DIR/p4".
|
|
||||||
The fetcher does not make use of a perforce client, instead it
|
|
||||||
relies on ``p4 files`` to retrieve a list of
|
|
||||||
files and ``p4 print`` to transfer the content
|
|
||||||
of those files locally.
|
|
||||||
|
|
||||||
To use this fetcher, make sure your recipe has proper
|
|
||||||
:term:`SRC_URI`, :term:`SRCREV`, and
|
|
||||||
:term:`PV` values. The p4 executable is able to use the
|
|
||||||
config file defined by your system's ``P4CONFIG`` environment variable
|
|
||||||
in order to define the Perforce server URL and port, username, and
|
|
||||||
password if you do not wish to keep those values in a recipe itself. If
|
|
||||||
you choose not to use ``P4CONFIG``, or to explicitly set variables that
|
|
||||||
``P4CONFIG`` can contain, you can specify the ``P4PORT`` value, which is
|
|
||||||
the server's URL and port number, and you can specify a username and
|
|
||||||
password directly in your recipe within :term:`SRC_URI`.
|
|
||||||
|
|
||||||
Here is an example that relies on ``P4CONFIG`` to specify the server URL
|
|
||||||
and port, username, and password, and fetches the Head Revision::
|
|
||||||
|
|
||||||
SRC_URI = "p4://example-depot/main/source/..."
|
|
||||||
SRCREV = "${AUTOREV}"
|
|
||||||
PV = "p4-${SRCPV}"
|
|
||||||
S = "${WORKDIR}/p4"
|
|
||||||
|
|
||||||
Here is an example that specifies the server URL and port, username, and
|
|
||||||
password, and fetches a Revision based on a Label::
|
|
||||||
|
|
||||||
P4PORT = "tcp:p4server.example.net:1666"
|
|
||||||
SRC_URI = "p4://user:passwd@example-depot/main/source/..."
|
|
||||||
SRCREV = "release-1.0"
|
|
||||||
PV = "p4-${SRCPV}"
|
|
||||||
S = "${WORKDIR}/p4"
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
You should always set S to "${WORKDIR}/p4" in your recipe.
|
|
||||||
|
|
||||||
By default, the fetcher strips the depot location from the local file paths. In
|
|
||||||
the above example, the content of ``example-depot/main/source/`` will be placed
|
|
||||||
in ``${WORKDIR}/p4``. For situations where preserving parts of the remote depot
|
|
||||||
paths locally is desirable, the fetcher supports two parameters:
|
|
||||||
|
|
||||||
- *"module":*
|
|
||||||
The top-level depot location or directory to fetch. The value of this
|
|
||||||
parameter can also point to a single file within the depot, in which case
|
|
||||||
the local file path will include the module path.
|
|
||||||
- *"remotepath":*
|
|
||||||
When used with the value "``keep``", the fetcher will mirror the full depot
|
|
||||||
paths locally for the specified location, even in combination with the
|
|
||||||
``module`` parameter.
|
|
||||||
|
|
||||||
Here is an example use of the the ``module`` parameter::
|
|
||||||
|
|
||||||
SRC_URI = "p4://user:passwd@example-depot/main;module=source/..."
|
|
||||||
|
|
||||||
In this case, the content of the top-level directory ``source/`` will be fetched
|
|
||||||
to ``${P4DIR}``, including the directory itself. The top-level directory will
|
|
||||||
be accesible at ``${P4DIR}/source/``.
|
|
||||||
|
|
||||||
Here is an example use of the the ``remotepath`` parameter::
|
|
||||||
|
|
||||||
SRC_URI = "p4://user:passwd@example-depot/main;module=source/...;remotepath=keep"
|
|
||||||
|
|
||||||
In this case, the content of the top-level directory ``source/`` will be fetched
|
|
||||||
to ``${P4DIR}``, but the complete depot paths will be mirrored locally. The
|
|
||||||
top-level directory will be accessible at
|
|
||||||
``${P4DIR}/example-depot/main/source/``.
|
|
||||||
|
|
||||||
.. _repo-fetcher:
|
|
||||||
|
|
||||||
Repo Fetcher (``repo://``)
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
This fetcher submodule fetches code from ``google-repo`` source control
|
|
||||||
system. The fetcher works by initiating and syncing sources of the
|
|
||||||
repository into :term:`REPODIR`, which is usually
|
|
||||||
``${DL_DIR}/repo``.
|
|
||||||
|
|
||||||
This fetcher supports the following parameters:
|
|
||||||
|
|
||||||
- *"protocol":* Protocol to fetch the repository manifest (default:
|
|
||||||
git).
|
|
||||||
|
|
||||||
- *"branch":* Branch or tag of repository to get (default: master).
|
|
||||||
|
|
||||||
- *"manifest":* Name of the manifest file (default: ``default.xml``).
|
|
||||||
|
|
||||||
Here are some example URLs::
|
|
||||||
|
|
||||||
SRC_URI = "repo://REPOROOT;protocol=git;branch=some_branch;manifest=my_manifest.xml"
|
|
||||||
SRC_URI = "repo://REPOROOT;protocol=file;branch=some_branch;manifest=my_manifest.xml"
|
|
||||||
|
|
||||||
.. _az-fetcher:
|
|
||||||
|
|
||||||
Az Fetcher (``az://``)
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
This submodule fetches data from an
|
|
||||||
`Azure Storage account <https://docs.microsoft.com/en-us/azure/storage/>`__ ,
|
|
||||||
it inherits its functionality from the HTTP wget fetcher, but modifies its
|
|
||||||
behavior to accomodate the usage of a
|
|
||||||
`Shared Access Signature (SAS) <https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview>`__
|
|
||||||
for non-public data.
|
|
||||||
|
|
||||||
Such functionality is set by the variable:
|
|
||||||
|
|
||||||
- :term:`AZ_SAS`: The Azure Storage Shared Access Signature provides secure
|
|
||||||
delegate access to resources, if this variable is set, the Az Fetcher will
|
|
||||||
use it when fetching artifacts from the cloud.
|
|
||||||
|
|
||||||
You can specify the AZ_SAS variable as shown below::
|
|
||||||
|
|
||||||
AZ_SAS = "se=2021-01-01&sp=r&sv=2018-11-09&sr=c&skoid=<skoid>&sig=<signature>"
|
|
||||||
|
|
||||||
Here is an example URL::
|
|
||||||
|
|
||||||
SRC_URI = "az://<azure-storage-account>.blob.core.windows.net/<foo_container>/<bar_file>"
|
|
||||||
|
|
||||||
It can also be used when setting mirrors definitions using the :term:`PREMIRRORS` variable.
|
|
||||||
|
|
||||||
.. _gcp-fetcher:
|
|
||||||
|
|
||||||
GCP Fetcher (``gs://``)
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
This submodule fetches data from a
|
|
||||||
`Google Cloud Storage Bucket <https://cloud.google.com/storage/docs/buckets>`__.
|
|
||||||
It uses the `Google Cloud Storage Python Client <https://cloud.google.com/python/docs/reference/storage/latest>`__
|
|
||||||
to check the status of objects in the bucket and download them.
|
|
||||||
The use of the Python client makes it substantially faster than using command
|
|
||||||
line tools such as gsutil.
|
|
||||||
|
|
||||||
The fetcher requires the Google Cloud Storage Python Client to be installed, along
|
|
||||||
with the gsutil tool.
|
|
||||||
|
|
||||||
The fetcher requires that the machine has valid credentials for accessing the
|
|
||||||
chosen bucket. Instructions for authentication can be found in the
|
|
||||||
`Google Cloud documentation <https://cloud.google.com/docs/authentication/provide-credentials-adc#local-dev>`__.
|
|
||||||
|
|
||||||
If it used from the OpenEmbedded build system, the fetcher can be used for
|
|
||||||
fetching sstate artifacts from a GCS bucket by specifying the
|
|
||||||
``SSTATE_MIRRORS`` variable as shown below::
|
|
||||||
|
|
||||||
SSTATE_MIRRORS ?= "\
|
|
||||||
file://.* gs://<bucket name>/PATH \
|
|
||||||
"
|
|
||||||
|
|
||||||
The fetcher can also be used in recipes::
|
|
||||||
|
|
||||||
SRC_URI = "gs://<bucket name>/<foo_container>/<bar_file>"
|
|
||||||
|
|
||||||
However, the checksum of the file should be also be provided::
|
|
||||||
|
|
||||||
SRC_URI[sha256sum] = "<sha256 string>"
|
|
||||||
|
|
||||||
.. _crate-fetcher:
|
|
||||||
|
|
||||||
Crate Fetcher (``crate://``)
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
This submodule fetches code for
|
|
||||||
`Rust language "crates" <https://doc.rust-lang.org/reference/glossary.html?highlight=crate#crate>`__
|
|
||||||
corresponding to Rust libraries and programs to compile. Such crates are typically shared
|
|
||||||
on https://crates.io/ but this fetcher supports other crate registries too.
|
|
||||||
|
|
||||||
The format for the :term:`SRC_URI` setting must be::
|
|
||||||
|
|
||||||
SRC_URI = "crate://REGISTRY/NAME/VERSION"
|
|
||||||
|
|
||||||
Here is an example URL::
|
|
||||||
|
|
||||||
SRC_URI = "crate://crates.io/glob/0.2.11"
|
|
||||||
|
|
||||||
.. _npm-fetcher:
|
|
||||||
|
|
||||||
NPM Fetcher (``npm://``)
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
This submodule fetches source code from an
|
|
||||||
`NPM <https://en.wikipedia.org/wiki/Npm_(software)>`__
|
|
||||||
Javascript package registry.
|
|
||||||
|
|
||||||
The format for the :term:`SRC_URI` setting must be::
|
|
||||||
|
|
||||||
SRC_URI = "npm://some.registry.url;ParameterA=xxx;ParameterB=xxx;..."
|
|
||||||
|
|
||||||
This fetcher supports the following parameters:
|
|
||||||
|
|
||||||
- *"package":* The NPM package name. This is a mandatory parameter.
|
|
||||||
|
|
||||||
- *"version":* The NPM package version. This is a mandatory parameter.
|
|
||||||
|
|
||||||
- *"downloadfilename":* Specifies the filename used when storing the downloaded file.
|
|
||||||
|
|
||||||
- *"destsuffix":* Specifies the directory to use to unpack the package (default: ``npm``).
|
|
||||||
|
|
||||||
Note that NPM fetcher only fetches the package source itself. The dependencies
|
|
||||||
can be fetched through the `npmsw-fetcher`_.
|
|
||||||
|
|
||||||
Here is an example URL with both fetchers::
|
|
||||||
|
|
||||||
SRC_URI = " \
|
|
||||||
npm://registry.npmjs.org/;package=cute-files;version=${PV} \
|
|
||||||
npmsw://${THISDIR}/${BPN}/npm-shrinkwrap.json \
|
|
||||||
"
|
|
||||||
|
|
||||||
See :yocto_docs:`Creating Node Package Manager (NPM) Packages
|
|
||||||
</dev-manual/packages.html#creating-node-package-manager-npm-packages>`
|
|
||||||
in the Yocto Project manual for details about using
|
|
||||||
:yocto_docs:`devtool <https://docs.yoctoproject.org/ref-manual/devtool-reference.html>`
|
|
||||||
to automatically create a recipe from an NPM URL.
|
|
||||||
|
|
||||||
.. _npmsw-fetcher:
|
|
||||||
|
|
||||||
NPM shrinkwrap Fetcher (``npmsw://``)
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
This submodule fetches source code from an
|
|
||||||
`NPM shrinkwrap <https://docs.npmjs.com/cli/v8/commands/npm-shrinkwrap>`__
|
|
||||||
description file, which lists the dependencies
|
|
||||||
of an NPM package while locking their versions.
|
|
||||||
|
|
||||||
The format for the :term:`SRC_URI` setting must be::
|
|
||||||
|
|
||||||
SRC_URI = "npmsw://some.registry.url;ParameterA=xxx;ParameterB=xxx;..."
|
|
||||||
|
|
||||||
This fetcher supports the following parameters:
|
|
||||||
|
|
||||||
- *"dev":* Set this parameter to ``1`` to install "devDependencies".
|
|
||||||
|
|
||||||
- *"destsuffix":* Specifies the directory to use to unpack the dependencies
|
|
||||||
(``${S}`` by default).
|
|
||||||
|
|
||||||
Note that the shrinkwrap file can also be provided by the recipe for
|
|
||||||
the package which has such dependencies, for example::
|
|
||||||
|
|
||||||
SRC_URI = " \
|
|
||||||
npm://registry.npmjs.org/;package=cute-files;version=${PV} \
|
|
||||||
npmsw://${THISDIR}/${BPN}/npm-shrinkwrap.json \
|
|
||||||
"
|
|
||||||
|
|
||||||
Such a file can automatically be generated using
|
|
||||||
:yocto_docs:`devtool <https://docs.yoctoproject.org/ref-manual/devtool-reference.html>`
|
|
||||||
as described in the :yocto_docs:`Creating Node Package Manager (NPM) Packages
|
|
||||||
</dev-manual/packages.html#creating-node-package-manager-npm-packages>`
|
|
||||||
section of the Yocto Project.
|
|
||||||
|
|
||||||
Other Fetchers
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Fetch submodules also exist for the following:
|
|
||||||
|
|
||||||
- Bazaar (``bzr://``)
|
|
||||||
|
|
||||||
- Mercurial (``hg://``)
|
|
||||||
|
|
||||||
- OSC (``osc://``)
|
|
||||||
|
|
||||||
- S3 (``s3://``)
|
|
||||||
|
|
||||||
- Secure FTP (``sftp://``)
|
|
||||||
|
|
||||||
- Secure Shell (``ssh://``)
|
|
||||||
|
|
||||||
- Trees using Git Annex (``gitannex://``)
|
|
||||||
|
|
||||||
No documentation currently exists for these lesser used fetcher
|
|
||||||
submodules. However, you might find the code helpful and readable.
|
|
||||||
|
|
||||||
Auto Revisions
|
|
||||||
==============
|
|
||||||
|
|
||||||
We need to document ``AUTOREV`` and :term:`SRCREV_FORMAT` here.
|
|
||||||
865
bitbake/doc/bitbake-user-manual/bitbake-user-manual-fetching.xml
Normal file
865
bitbake/doc/bitbake-user-manual/bitbake-user-manual-fetching.xml
Normal file
@@ -0,0 +1,865 @@
|
|||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<chapter>
|
||||||
|
<title>File Download Support</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake's fetch module is a standalone piece of library code
|
||||||
|
that deals with the intricacies of downloading source code
|
||||||
|
and files from remote systems.
|
||||||
|
Fetching source code is one of the cornerstones of building software.
|
||||||
|
As such, this module forms an important part of BitBake.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The current fetch module is called "fetch2" and refers to the
|
||||||
|
fact that it is the second major version of the API.
|
||||||
|
The original version is obsolete and has been removed from the codebase.
|
||||||
|
Thus, in all cases, "fetch" refers to "fetch2" in this
|
||||||
|
manual.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id='the-download-fetch'>
|
||||||
|
<title>The Download (Fetch)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake takes several steps when fetching source code or files.
|
||||||
|
The fetcher codebase deals with two distinct processes in order:
|
||||||
|
obtaining the files from somewhere (cached or otherwise)
|
||||||
|
and then unpacking those files into a specific location and
|
||||||
|
perhaps in a specific way.
|
||||||
|
Getting and unpacking the files is often optionally followed
|
||||||
|
by patching.
|
||||||
|
Patching, however, is not covered by this module.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The code to execute the first part of this process, a fetch,
|
||||||
|
looks something like the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
src_uri = (d.getVar('SRC_URI') or "").split()
|
||||||
|
fetcher = bb.fetch2.Fetch(src_uri, d)
|
||||||
|
fetcher.download()
|
||||||
|
</literallayout>
|
||||||
|
This code sets up an instance of the fetch class.
|
||||||
|
The instance uses a space-separated list of URLs from the
|
||||||
|
<link linkend='var-bb-SRC_URI'><filename>SRC_URI</filename></link>
|
||||||
|
variable and then calls the <filename>download</filename>
|
||||||
|
method to download the files.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The instantiation of the fetch class is usually followed by:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
rootdir = l.getVar('WORKDIR')
|
||||||
|
fetcher.unpack(rootdir)
|
||||||
|
</literallayout>
|
||||||
|
This code unpacks the downloaded files to the
|
||||||
|
specified by <filename>WORKDIR</filename>.
|
||||||
|
<note>
|
||||||
|
For convenience, the naming in these examples matches
|
||||||
|
the variables used by OpenEmbedded.
|
||||||
|
If you want to see the above code in action, examine
|
||||||
|
the OpenEmbedded class file <filename>base.bbclass</filename>.
|
||||||
|
</note>
|
||||||
|
The <filename>SRC_URI</filename> and <filename>WORKDIR</filename>
|
||||||
|
variables are not hardcoded into the fetcher, since those fetcher
|
||||||
|
methods can be (and are) called with different variable names.
|
||||||
|
In OpenEmbedded for example, the shared state (sstate) code uses
|
||||||
|
the fetch module to fetch the sstate files.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When the <filename>download()</filename> method is called,
|
||||||
|
BitBake tries to resolve the URLs by looking for source files
|
||||||
|
in a specific search order:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><emphasis>Pre-mirror Sites:</emphasis>
|
||||||
|
BitBake first uses pre-mirrors to try and find source files.
|
||||||
|
These locations are defined using the
|
||||||
|
<link linkend='var-bb-PREMIRRORS'><filename>PREMIRRORS</filename></link>
|
||||||
|
variable.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Source URI:</emphasis>
|
||||||
|
If pre-mirrors fail, BitBake uses the original URL (e.g from
|
||||||
|
<filename>SRC_URI</filename>).
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Mirror Sites:</emphasis>
|
||||||
|
If fetch failures occur, BitBake next uses mirror locations as
|
||||||
|
defined by the
|
||||||
|
<link linkend='var-bb-MIRRORS'><filename>MIRRORS</filename></link>
|
||||||
|
variable.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For each URL passed to the fetcher, the fetcher
|
||||||
|
calls the submodule that handles that particular URL type.
|
||||||
|
This behavior can be the source of some confusion when you
|
||||||
|
are providing URLs for the <filename>SRC_URI</filename>
|
||||||
|
variable.
|
||||||
|
Consider the following two URLs:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
http://git.yoctoproject.org/git/poky;protocol=git
|
||||||
|
git://git.yoctoproject.org/git/poky;protocol=http
|
||||||
|
</literallayout>
|
||||||
|
In the former case, the URL is passed to the
|
||||||
|
<filename>wget</filename> fetcher, which does not
|
||||||
|
understand "git".
|
||||||
|
Therefore, the latter case is the correct form since the
|
||||||
|
Git fetcher does know how to use HTTP as a transport.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Here are some examples that show commonly used mirror
|
||||||
|
definitions:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
PREMIRRORS ?= "\
|
||||||
|
bzr://.*/.* http://somemirror.org/sources/ \n \
|
||||||
|
cvs://.*/.* http://somemirror.org/sources/ \n \
|
||||||
|
git://.*/.* http://somemirror.org/sources/ \n \
|
||||||
|
hg://.*/.* http://somemirror.org/sources/ \n \
|
||||||
|
osc://.*/.* http://somemirror.org/sources/ \n \
|
||||||
|
p4://.*/.* http://somemirror.org/sources/ \n \
|
||||||
|
svn://.*/.* http://somemirror.org/sources/ \n"
|
||||||
|
|
||||||
|
MIRRORS =+ "\
|
||||||
|
ftp://.*/.* http://somemirror.org/sources/ \n \
|
||||||
|
http://.*/.* http://somemirror.org/sources/ \n \
|
||||||
|
https://.*/.* http://somemirror.org/sources/ \n"
|
||||||
|
</literallayout>
|
||||||
|
It is useful to note that BitBake supports
|
||||||
|
cross-URLs.
|
||||||
|
It is possible to mirror a Git repository on an HTTP
|
||||||
|
server as a tarball.
|
||||||
|
This is what the <filename>git://</filename> mapping in
|
||||||
|
the previous example does.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Since network accesses are slow, Bitbake maintains a
|
||||||
|
cache of files downloaded from the network.
|
||||||
|
Any source files that are not local (i.e.
|
||||||
|
downloaded from the Internet) are placed into the download
|
||||||
|
directory, which is specified by the
|
||||||
|
<link linkend='var-bb-DL_DIR'><filename>DL_DIR</filename></link>
|
||||||
|
variable.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
File integrity is of key importance for reproducing builds.
|
||||||
|
For non-local archive downloads, the fetcher code can verify
|
||||||
|
SHA-256 and MD5 checksums to ensure the archives have been
|
||||||
|
downloaded correctly.
|
||||||
|
You can specify these checksums by using the
|
||||||
|
<filename>SRC_URI</filename> variable with the appropriate
|
||||||
|
varflags as follows:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI[md5sum] = "<replaceable>value</replaceable>"
|
||||||
|
SRC_URI[sha256sum] = "<replaceable>value</replaceable>"
|
||||||
|
</literallayout>
|
||||||
|
You can also specify the checksums as parameters on the
|
||||||
|
<filename>SRC_URI</filename> as shown below:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "http://example.com/foobar.tar.bz2;md5sum=4a8e0f237e961fd7785d19d07fdb994d"
|
||||||
|
</literallayout>
|
||||||
|
If multiple URIs exist, you can specify the checksums either
|
||||||
|
directly as in the previous example, or you can name the URLs.
|
||||||
|
The following syntax shows how you name the URIs:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "http://example.com/foobar.tar.bz2;name=foo"
|
||||||
|
SRC_URI[foo.md5sum] = 4a8e0f237e961fd7785d19d07fdb994d
|
||||||
|
</literallayout>
|
||||||
|
After a file has been downloaded and has had its checksum checked,
|
||||||
|
a ".done" stamp is placed in <filename>DL_DIR</filename>.
|
||||||
|
BitBake uses this stamp during subsequent builds to avoid
|
||||||
|
downloading or comparing a checksum for the file again.
|
||||||
|
<note>
|
||||||
|
It is assumed that local storage is safe from data corruption.
|
||||||
|
If this were not the case, there would be bigger issues to worry about.
|
||||||
|
</note>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If
|
||||||
|
<link linkend='var-bb-BB_STRICT_CHECKSUM'><filename>BB_STRICT_CHECKSUM</filename></link>
|
||||||
|
is set, any download without a checksum triggers an
|
||||||
|
error message.
|
||||||
|
The
|
||||||
|
<link linkend='var-bb-BB_NO_NETWORK'><filename>BB_NO_NETWORK</filename></link>
|
||||||
|
variable can be used to make any attempted network access a fatal
|
||||||
|
error, which is useful for checking that mirrors are complete
|
||||||
|
as well as other things.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bb-the-unpack'>
|
||||||
|
<title>The Unpack</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The unpack process usually immediately follows the download.
|
||||||
|
For all URLs except Git URLs, BitBake uses the common
|
||||||
|
<filename>unpack</filename> method.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A number of parameters exist that you can specify within the
|
||||||
|
URL to govern the behavior of the unpack stage:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><emphasis>unpack:</emphasis>
|
||||||
|
Controls whether the URL components are unpacked.
|
||||||
|
If set to "1", which is the default, the components
|
||||||
|
are unpacked.
|
||||||
|
If set to "0", the unpack stage leaves the file alone.
|
||||||
|
This parameter is useful when you want an archive to be
|
||||||
|
copied in and not be unpacked.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>dos:</emphasis>
|
||||||
|
Applies to <filename>.zip</filename> and
|
||||||
|
<filename>.jar</filename> files and specifies whether to
|
||||||
|
use DOS line ending conversion on text files.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>basepath:</emphasis>
|
||||||
|
Instructs the unpack stage to strip the specified
|
||||||
|
directories from the source path when unpacking.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>subdir:</emphasis>
|
||||||
|
Unpacks the specific URL to the specified subdirectory
|
||||||
|
within the root directory.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
The unpack call automatically decompresses and extracts files
|
||||||
|
with ".Z", ".z", ".gz", ".xz", ".zip", ".jar", ".ipk", ".rpm".
|
||||||
|
".srpm", ".deb" and ".bz2" extensions as well as various combinations
|
||||||
|
of tarball extensions.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As mentioned, the Git fetcher has its own unpack method that
|
||||||
|
is optimized to work with Git trees.
|
||||||
|
Basically, this method works by cloning the tree into the final
|
||||||
|
directory.
|
||||||
|
The process is completed using references so that there is
|
||||||
|
only one central copy of the Git metadata needed.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bb-fetchers'>
|
||||||
|
<title>Fetchers</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As mentioned earlier, the URL prefix determines which
|
||||||
|
fetcher submodule BitBake uses.
|
||||||
|
Each submodule can support different URL parameters,
|
||||||
|
which are described in the following sections.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id='local-file-fetcher'>
|
||||||
|
<title>Local file fetcher (<filename>file://</filename>)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This submodule handles URLs that begin with
|
||||||
|
<filename>file://</filename>.
|
||||||
|
The filename you specify within the URL can be
|
||||||
|
either an absolute or relative path to a file.
|
||||||
|
If the filename is relative, the contents of the
|
||||||
|
<link linkend='var-bb-FILESPATH'><filename>FILESPATH</filename></link>
|
||||||
|
variable is used in the same way
|
||||||
|
<filename>PATH</filename> is used to find executables.
|
||||||
|
If the file cannot be found, it is assumed that it is available in
|
||||||
|
<link linkend='var-bb-DL_DIR'><filename>DL_DIR</filename></link>
|
||||||
|
by the time the <filename>download()</filename> method is called.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If you specify a directory, the entire directory is
|
||||||
|
unpacked.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Here are a couple of example URLs, the first relative and
|
||||||
|
the second absolute:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "file://relativefile.patch"
|
||||||
|
SRC_URI = "file:///Users/ich/very_important_software"
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='http-ftp-fetcher'>
|
||||||
|
<title>HTTP/FTP wget fetcher (<filename>http://</filename>, <filename>ftp://</filename>, <filename>https://</filename>)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This fetcher obtains files from web and FTP servers.
|
||||||
|
Internally, the fetcher uses the wget utility.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The executable and parameters used are specified by the
|
||||||
|
<filename>FETCHCMD_wget</filename> variable, which defaults
|
||||||
|
to sensible values.
|
||||||
|
The fetcher supports a parameter "downloadfilename" that
|
||||||
|
allows the name of the downloaded file to be specified.
|
||||||
|
Specifying the name of the downloaded file is useful
|
||||||
|
for avoiding collisions in
|
||||||
|
<link linkend='var-bb-DL_DIR'><filename>DL_DIR</filename></link>
|
||||||
|
when dealing with multiple files that have the same name.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Some example URLs are as follows:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "http://oe.handhelds.org/not_there.aac"
|
||||||
|
SRC_URI = "ftp://oe.handhelds.org/not_there_as_well.aac"
|
||||||
|
SRC_URI = "ftp://you@oe.handhelds.org/home/you/secret.plan"
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
<note>
|
||||||
|
Because URL parameters are delimited by semi-colons, this can
|
||||||
|
introduce ambiguity when parsing URLs that also contain semi-colons,
|
||||||
|
for example:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git;a=snapshot;h=a5dd47"
|
||||||
|
</literallayout>
|
||||||
|
Such URLs should should be modified by replacing semi-colons with '&' characters:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git&a=snapshot&h=a5dd47"
|
||||||
|
</literallayout>
|
||||||
|
In most cases this should work. Treating semi-colons and '&' in queries
|
||||||
|
identically is recommended by the World Wide Web Consortium (W3C).
|
||||||
|
Note that due to the nature of the URL, you may have to specify the name
|
||||||
|
of the downloaded file as well:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git&a=snapshot&h=a5dd47;downloadfilename=myfile.bz2"
|
||||||
|
</literallayout>
|
||||||
|
</note>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='cvs-fetcher'>
|
||||||
|
<title>CVS fetcher (<filename>(cvs://</filename>)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This submodule handles checking out files from the
|
||||||
|
CVS version control system.
|
||||||
|
You can configure it using a number of different variables:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><emphasis><filename>FETCHCMD_cvs</filename>:</emphasis>
|
||||||
|
The name of the executable to use when running
|
||||||
|
the <filename>cvs</filename> command.
|
||||||
|
This name is usually "cvs".
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis><filename>SRCDATE</filename>:</emphasis>
|
||||||
|
The date to use when fetching the CVS source code.
|
||||||
|
A special value of "now" causes the checkout to
|
||||||
|
be updated on every build.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis><link linkend='var-bb-CVSDIR'><filename>CVSDIR</filename></link>:</emphasis>
|
||||||
|
Specifies where a temporary checkout is saved.
|
||||||
|
The location is often <filename>DL_DIR/cvs</filename>.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis><filename>CVS_PROXY_HOST</filename>:</emphasis>
|
||||||
|
The name to use as a "proxy=" parameter to the
|
||||||
|
<filename>cvs</filename> command.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis><filename>CVS_PROXY_PORT</filename>:</emphasis>
|
||||||
|
The port number to use as a "proxyport=" parameter to
|
||||||
|
the <filename>cvs</filename> command.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
As well as the standard username and password URL syntax,
|
||||||
|
you can also configure the fetcher with various URL parameters:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The supported parameters are as follows:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><emphasis>"method":</emphasis>
|
||||||
|
The protocol over which to communicate with the CVS
|
||||||
|
server.
|
||||||
|
By default, this protocol is "pserver".
|
||||||
|
If "method" is set to "ext", BitBake examines the
|
||||||
|
"rsh" parameter and sets <filename>CVS_RSH</filename>.
|
||||||
|
You can use "dir" for local directories.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"module":</emphasis>
|
||||||
|
Specifies the module to check out.
|
||||||
|
You must supply this parameter.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"tag":</emphasis>
|
||||||
|
Describes which CVS TAG should be used for
|
||||||
|
the checkout.
|
||||||
|
By default, the TAG is empty.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"date":</emphasis>
|
||||||
|
Specifies a date.
|
||||||
|
If no "date" is specified, the
|
||||||
|
<link linkend='var-bb-SRCDATE'><filename>SRCDATE</filename></link>
|
||||||
|
of the configuration is used to checkout a specific date.
|
||||||
|
The special value of "now" causes the checkout to be
|
||||||
|
updated on every build.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"localdir":</emphasis>
|
||||||
|
Used to rename the module.
|
||||||
|
Effectively, you are renaming the output directory
|
||||||
|
to which the module is unpacked.
|
||||||
|
You are forcing the module into a special
|
||||||
|
directory relative to
|
||||||
|
<link linkend='var-bb-CVSDIR'><filename>CVSDIR</filename></link>.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"rsh"</emphasis>
|
||||||
|
Used in conjunction with the "method" parameter.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"scmdata":</emphasis>
|
||||||
|
Causes the CVS metadata to be maintained in the tarball
|
||||||
|
the fetcher creates when set to "keep".
|
||||||
|
The tarball is expanded into the work directory.
|
||||||
|
By default, the CVS metadata is removed.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"fullpath":</emphasis>
|
||||||
|
Controls whether the resulting checkout is at the
|
||||||
|
module level, which is the default, or is at deeper
|
||||||
|
paths.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"norecurse":</emphasis>
|
||||||
|
Causes the fetcher to only checkout the specified
|
||||||
|
directory with no recurse into any subdirectories.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"port":</emphasis>
|
||||||
|
The port to which the CVS server connects.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
Some example URLs are as follows:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "cvs://CVSROOT;module=mymodule;tag=some-version;method=ext"
|
||||||
|
SRC_URI = "cvs://CVSROOT;module=mymodule;date=20060126;localdir=usethat"
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='svn-fetcher'>
|
||||||
|
<title>Subversion (SVN) Fetcher (<filename>svn://</filename>)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This fetcher submodule fetches code from the
|
||||||
|
Subversion source control system.
|
||||||
|
The executable used is specified by
|
||||||
|
<filename>FETCHCMD_svn</filename>, which defaults
|
||||||
|
to "svn".
|
||||||
|
The fetcher's temporary working directory is set by
|
||||||
|
<link linkend='var-bb-SVNDIR'><filename>SVNDIR</filename></link>,
|
||||||
|
which is usually <filename>DL_DIR/svn</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The supported parameters are as follows:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><emphasis>"module":</emphasis>
|
||||||
|
The name of the svn module to checkout.
|
||||||
|
You must provide this parameter.
|
||||||
|
You can think of this parameter as the top-level
|
||||||
|
directory of the repository data you want.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"path_spec":</emphasis>
|
||||||
|
A specific directory in which to checkout the
|
||||||
|
specified svn module.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"protocol":</emphasis>
|
||||||
|
The protocol to use, which defaults to "svn".
|
||||||
|
If "protocol" is set to "svn+ssh", the "ssh"
|
||||||
|
parameter is also used.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"rev":</emphasis>
|
||||||
|
The revision of the source code to checkout.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"scmdata":</emphasis>
|
||||||
|
Causes the “.svn” directories to be available during
|
||||||
|
compile-time when set to "keep".
|
||||||
|
By default, these directories are removed.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"ssh":</emphasis>
|
||||||
|
An optional parameter used when "protocol" is set
|
||||||
|
to "svn+ssh".
|
||||||
|
You can use this parameter to specify the ssh
|
||||||
|
program used by svn.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"transportuser":</emphasis>
|
||||||
|
When required, sets the username for the transport.
|
||||||
|
By default, this parameter is empty.
|
||||||
|
The transport username is different than the username
|
||||||
|
used in the main URL, which is passed to the subversion
|
||||||
|
command.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
Following are three examples using svn:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "svn://myrepos/proj1;module=vip;protocol=http;rev=667"
|
||||||
|
SRC_URI = "svn://myrepos/proj1;module=opie;protocol=svn+ssh"
|
||||||
|
SRC_URI = "svn://myrepos/proj1;module=trunk;protocol=http;path_spec=${MY_DIR}/proj1"
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='git-fetcher'>
|
||||||
|
<title>Git Fetcher (<filename>git://</filename>)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This fetcher submodule fetches code from the Git
|
||||||
|
source control system.
|
||||||
|
The fetcher works by creating a bare clone of the
|
||||||
|
remote into
|
||||||
|
<link linkend='var-bb-GITDIR'><filename>GITDIR</filename></link>,
|
||||||
|
which is usually <filename>DL_DIR/git2</filename>.
|
||||||
|
This bare clone is then cloned into the work directory during the
|
||||||
|
unpack stage when a specific tree is checked out.
|
||||||
|
This is done using alternates and by reference to
|
||||||
|
minimize the amount of duplicate data on the disk and
|
||||||
|
make the unpack process fast.
|
||||||
|
The executable used can be set with
|
||||||
|
<filename>FETCHCMD_git</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This fetcher supports the following parameters:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><emphasis>"protocol":</emphasis>
|
||||||
|
The protocol used to fetch the files.
|
||||||
|
The default is "git" when a hostname is set.
|
||||||
|
If a hostname is not set, the Git protocol is "file".
|
||||||
|
You can also use "http", "https", "ssh" and "rsync".
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"nocheckout":</emphasis>
|
||||||
|
Tells the fetcher to not checkout source code when
|
||||||
|
unpacking when set to "1".
|
||||||
|
Set this option for the URL where there is a custom
|
||||||
|
routine to checkout code.
|
||||||
|
The default is "0".
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"rebaseable":</emphasis>
|
||||||
|
Indicates that the upstream Git repository can be rebased.
|
||||||
|
You should set this parameter to "1" if
|
||||||
|
revisions can become detached from branches.
|
||||||
|
In this case, the source mirror tarball is done per
|
||||||
|
revision, which has a loss of efficiency.
|
||||||
|
Rebasing the upstream Git repository could cause the
|
||||||
|
current revision to disappear from the upstream repository.
|
||||||
|
This option reminds the fetcher to preserve the local cache
|
||||||
|
carefully for future use.
|
||||||
|
The default value for this parameter is "0".
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"nobranch":</emphasis>
|
||||||
|
Tells the fetcher to not check the SHA validation
|
||||||
|
for the branch when set to "1".
|
||||||
|
The default is "0".
|
||||||
|
Set this option for the recipe that refers to
|
||||||
|
the commit that is valid for a tag instead of
|
||||||
|
the branch.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"bareclone":</emphasis>
|
||||||
|
Tells the fetcher to clone a bare clone into the
|
||||||
|
destination directory without checking out a working tree.
|
||||||
|
Only the raw Git metadata is provided.
|
||||||
|
This parameter implies the "nocheckout" parameter as well.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"branch":</emphasis>
|
||||||
|
The branch(es) of the Git tree to clone.
|
||||||
|
If unset, this is assumed to be "master".
|
||||||
|
The number of branch parameters much match the number of
|
||||||
|
name parameters.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"rev":</emphasis>
|
||||||
|
The revision to use for the checkout.
|
||||||
|
The default is "master".
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"tag":</emphasis>
|
||||||
|
Specifies a tag to use for the checkout.
|
||||||
|
To correctly resolve tags, BitBake must access the
|
||||||
|
network.
|
||||||
|
For that reason, tags are often not used.
|
||||||
|
As far as Git is concerned, the "tag" parameter behaves
|
||||||
|
effectively the same as the "rev" parameter.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"subpath":</emphasis>
|
||||||
|
Limits the checkout to a specific subpath of the tree.
|
||||||
|
By default, the whole tree is checked out.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"destsuffix":</emphasis>
|
||||||
|
The name of the path in which to place the checkout.
|
||||||
|
By default, the path is <filename>git/</filename>.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>"usehead":</emphasis>
|
||||||
|
Enables local <filename>git://</filename> URLs to use the
|
||||||
|
current branch HEAD as the revision for use with
|
||||||
|
<filename>AUTOREV</filename>.
|
||||||
|
The "usehead" parameter implies no branch and only works
|
||||||
|
when the transfer protocol is
|
||||||
|
<filename>file://</filename>.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
Here are some example URLs:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "git://git.oe.handhelds.org/git/vip.git;tag=version-1"
|
||||||
|
SRC_URI = "git://git.oe.handhelds.org/git/vip.git;protocol=http"
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='gitsm-fetcher'>
|
||||||
|
<title>Git Submodule Fetcher (<filename>gitsm://</filename>)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This fetcher submodule inherits from the
|
||||||
|
<link linkend='git-fetcher'>Git fetcher</link> and extends
|
||||||
|
that fetcher's behavior by fetching a repository's submodules.
|
||||||
|
<link linkend='var-bb-SRC_URI'><filename>SRC_URI</filename></link>
|
||||||
|
is passed to the Git fetcher as described in the
|
||||||
|
"<link linkend='git-fetcher'>Git Fetcher (<filename>git://</filename>)</link>"
|
||||||
|
section.
|
||||||
|
<note>
|
||||||
|
<title>Notes and Warnings</title>
|
||||||
|
<para>
|
||||||
|
You must clean a recipe when switching between
|
||||||
|
'<filename>git://</filename>' and
|
||||||
|
'<filename>gitsm://</filename>' URLs.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The Git Submodules fetcher is not a complete fetcher
|
||||||
|
implementation.
|
||||||
|
The fetcher has known issues where it does not use the
|
||||||
|
normal source mirroring infrastructure properly. Further,
|
||||||
|
the submodule sources it fetches are not visible to the
|
||||||
|
licensing and source archiving infrastructures.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='clearcase-fetcher'>
|
||||||
|
<title>ClearCase Fetcher (<filename>ccrc://</filename>)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This fetcher submodule fetches code from a
|
||||||
|
<ulink url='http://en.wikipedia.org/wiki/Rational_ClearCase'>ClearCase</ulink>
|
||||||
|
repository.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To use this fetcher, make sure your recipe has proper
|
||||||
|
<link linkend='var-bb-SRC_URI'><filename>SRC_URI</filename></link>,
|
||||||
|
<link linkend='var-bb-SRCREV'><filename>SRCREV</filename></link>, and
|
||||||
|
<link linkend='var-bb-PV'><filename>PV</filename></link> settings.
|
||||||
|
Here is an example:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "ccrc://cc.example.org/ccrc;vob=/example_vob;module=/example_module"
|
||||||
|
SRCREV = "EXAMPLE_CLEARCASE_TAG"
|
||||||
|
PV = "${@d.getVar("SRCREV", False).replace("/", "+")}"
|
||||||
|
</literallayout>
|
||||||
|
The fetcher uses the <filename>rcleartool</filename> or
|
||||||
|
<filename>cleartool</filename> remote client, depending on
|
||||||
|
which one is available.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Following are options for the <filename>SRC_URI</filename>
|
||||||
|
statement:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><emphasis><filename>vob</filename></emphasis>:
|
||||||
|
The name, which must include the
|
||||||
|
prepending "/" character, of the ClearCase VOB.
|
||||||
|
This option is required.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis><filename>module</filename></emphasis>:
|
||||||
|
The module, which must include the
|
||||||
|
prepending "/" character, in the selected VOB.
|
||||||
|
<note>
|
||||||
|
The <filename>module</filename> and <filename>vob</filename>
|
||||||
|
options are combined to create the <filename>load</filename> rule in
|
||||||
|
the view config spec.
|
||||||
|
As an example, consider the <filename>vob</filename> and
|
||||||
|
<filename>module</filename> values from the
|
||||||
|
<filename>SRC_URI</filename> statement at the start of this section.
|
||||||
|
Combining those values results in the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
load /example_vob/example_module
|
||||||
|
</literallayout>
|
||||||
|
</note>
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis><filename>proto</filename></emphasis>:
|
||||||
|
The protocol, which can be either <filename>http</filename> or
|
||||||
|
<filename>https</filename>.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
By default, the fetcher creates a configuration specification.
|
||||||
|
If you want this specification written to an area other than the default,
|
||||||
|
use the <filename>CCASE_CUSTOM_CONFIG_SPEC</filename> variable
|
||||||
|
in your recipe to define where the specification is written.
|
||||||
|
<note>
|
||||||
|
the <filename>SRCREV</filename> loses its functionality if you
|
||||||
|
specify this variable.
|
||||||
|
However, <filename>SRCREV</filename> is still used to label the
|
||||||
|
archive after a fetch even though it does not define what is
|
||||||
|
fetched.
|
||||||
|
</note>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Here are a couple of other behaviors worth mentioning:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
When using <filename>cleartool</filename>, the login of
|
||||||
|
<filename>cleartool</filename> is handled by the system.
|
||||||
|
The login require no special steps.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
In order to use <filename>rcleartool</filename> with authenticated
|
||||||
|
users, an "rcleartool login" is necessary before using the fetcher.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='perforce-fetcher'>
|
||||||
|
<title>Perforce Fetcher (<filename>p4://</filename>)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This fetcher submodule fetches code from the
|
||||||
|
<ulink url='https://www.perforce.com/'>Perforce</ulink>
|
||||||
|
source control system.
|
||||||
|
The executable used is specified by
|
||||||
|
<filename>FETCHCMD_p4</filename>, which defaults
|
||||||
|
to "p4".
|
||||||
|
The fetcher's temporary working directory is set by
|
||||||
|
<link linkend='var-bb-P4DIR'><filename>P4DIR</filename></link>,
|
||||||
|
which defaults to "DL_DIR/p4".
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To use this fetcher, make sure your recipe has proper
|
||||||
|
<link linkend='var-bb-SRC_URI'><filename>SRC_URI</filename></link>,
|
||||||
|
<link linkend='var-bb-SRCREV'><filename>SRCREV</filename></link>, and
|
||||||
|
<link linkend='var-bb-PV'><filename>PV</filename></link> values.
|
||||||
|
The p4 executable is able to use the config file defined by your
|
||||||
|
system's <filename>P4CONFIG</filename> environment variable in
|
||||||
|
order to define the Perforce server URL and port, username, and
|
||||||
|
password if you do not wish to keep those values in a recipe
|
||||||
|
itself.
|
||||||
|
If you choose not to use <filename>P4CONFIG</filename>,
|
||||||
|
or to explicitly set variables that <filename>P4CONFIG</filename>
|
||||||
|
can contain, you can specify the <filename>P4PORT</filename> value,
|
||||||
|
which is the server's URL and port number, and you can
|
||||||
|
specify a username and password directly in your recipe within
|
||||||
|
<filename>SRC_URI</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Here is an example that relies on <filename>P4CONFIG</filename>
|
||||||
|
to specify the server URL and port, username, and password, and
|
||||||
|
fetches the Head Revision:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "p4://example-depot/main/source/..."
|
||||||
|
SRCREV = "${AUTOREV}"
|
||||||
|
PV = "p4-${SRCPV}"
|
||||||
|
S = "${WORKDIR}/p4"
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Here is an example that specifies the server URL and port,
|
||||||
|
username, and password, and fetches a Revision based on a Label:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
P4PORT = "tcp:p4server.example.net:1666"
|
||||||
|
SRC_URI = "p4://user:passwd@example-depot/main/source/..."
|
||||||
|
SRCREV = "release-1.0"
|
||||||
|
PV = "p4-${SRCPV}"
|
||||||
|
S = "${WORKDIR}/p4"
|
||||||
|
</literallayout>
|
||||||
|
<note>
|
||||||
|
You should always set <filename>S</filename>
|
||||||
|
to <filename>"${WORKDIR}/p4"</filename> in your recipe.
|
||||||
|
</note>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='repo-fetcher'>
|
||||||
|
<title>Repo Fetcher (<filename>repo://</filename>)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This fetcher submodule fetches code from
|
||||||
|
<filename>google-repo</filename> source control system.
|
||||||
|
The fetcher works by initiating and syncing sources of the
|
||||||
|
repository into
|
||||||
|
<link linkend='var-bb-REPODIR'><filename>REPODIR</filename></link>,
|
||||||
|
which is usually
|
||||||
|
<link linkend='var-bb-DL_DIR'><filename>DL_DIR</filename></link><filename>/repo</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This fetcher supports the following parameters:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
<emphasis>"protocol":</emphasis>
|
||||||
|
Protocol to fetch the repository manifest (default: git).
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
<emphasis>"branch":</emphasis>
|
||||||
|
Branch or tag of repository to get (default: master).
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
<emphasis>"manifest":</emphasis>
|
||||||
|
Name of the manifest file (default: <filename>default.xml</filename>).
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
Here are some example URLs:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
SRC_URI = "repo://REPOROOT;protocol=git;branch=some_branch;manifest=my_manifest.xml"
|
||||||
|
SRC_URI = "repo://REPOROOT;protocol=file;branch=some_branch;manifest=my_manifest.xml"
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='other-fetchers'>
|
||||||
|
<title>Other Fetchers</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Fetch submodules also exist for the following:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
Bazaar (<filename>bzr://</filename>)
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Trees using Git Annex (<filename>gitannex://</filename>)
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Secure FTP (<filename>sftp://</filename>)
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Secure Shell (<filename>ssh://</filename>)
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
OSC (<filename>osc://</filename>)
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Mercurial (<filename>hg://</filename>)
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
No documentation currently exists for these lesser used
|
||||||
|
fetcher submodules.
|
||||||
|
However, you might find the code helpful and readable.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='auto-revisions'>
|
||||||
|
<title>Auto Revisions</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We need to document <filename>AUTOREV</filename> and
|
||||||
|
<filename>SRCREV_FORMAT</filename> here.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</chapter>
|
||||||
@@ -1,408 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: CC-BY-2.5
|
|
||||||
|
|
||||||
===================
|
|
||||||
Hello World Example
|
|
||||||
===================
|
|
||||||
|
|
||||||
BitBake Hello World
|
|
||||||
===================
|
|
||||||
|
|
||||||
The simplest example commonly used to demonstrate any new programming
|
|
||||||
language or tool is the "`Hello
|
|
||||||
World <http://en.wikipedia.org/wiki/Hello_world_program>`__" example.
|
|
||||||
This appendix demonstrates, in tutorial form, Hello World within the
|
|
||||||
context of BitBake. The tutorial describes how to create a new project
|
|
||||||
and the applicable metadata files necessary to allow BitBake to build
|
|
||||||
it.
|
|
||||||
|
|
||||||
Obtaining BitBake
|
|
||||||
=================
|
|
||||||
|
|
||||||
See the :ref:`bitbake-user-manual/bitbake-user-manual-intro:obtaining bitbake` section for
|
|
||||||
information on how to obtain BitBake. Once you have the source code on
|
|
||||||
your machine, the BitBake directory appears as follows::
|
|
||||||
|
|
||||||
$ ls -al
|
|
||||||
total 108
|
|
||||||
drwxr-xr-x 9 fawkh 10000 4096 feb 24 12:10 .
|
|
||||||
drwx------ 36 fawkh 10000 4096 mar 2 17:00 ..
|
|
||||||
-rw-r--r-- 1 fawkh 10000 365 feb 24 12:10 AUTHORS
|
|
||||||
drwxr-xr-x 2 fawkh 10000 4096 feb 24 12:10 bin
|
|
||||||
-rw-r--r-- 1 fawkh 10000 16501 feb 24 12:10 ChangeLog
|
|
||||||
drwxr-xr-x 2 fawkh 10000 4096 feb 24 12:10 classes
|
|
||||||
drwxr-xr-x 2 fawkh 10000 4096 feb 24 12:10 conf
|
|
||||||
drwxr-xr-x 5 fawkh 10000 4096 feb 24 12:10 contrib
|
|
||||||
drwxr-xr-x 6 fawkh 10000 4096 feb 24 12:10 doc
|
|
||||||
drwxr-xr-x 8 fawkh 10000 4096 mar 2 16:26 .git
|
|
||||||
-rw-r--r-- 1 fawkh 10000 31 feb 24 12:10 .gitattributes
|
|
||||||
-rw-r--r-- 1 fawkh 10000 392 feb 24 12:10 .gitignore
|
|
||||||
drwxr-xr-x 13 fawkh 10000 4096 feb 24 12:11 lib
|
|
||||||
-rw-r--r-- 1 fawkh 10000 1224 feb 24 12:10 LICENSE
|
|
||||||
-rw-r--r-- 1 fawkh 10000 15394 feb 24 12:10 LICENSE.GPL-2.0-only
|
|
||||||
-rw-r--r-- 1 fawkh 10000 1286 feb 24 12:10 LICENSE.MIT
|
|
||||||
-rw-r--r-- 1 fawkh 10000 229 feb 24 12:10 MANIFEST.in
|
|
||||||
-rw-r--r-- 1 fawkh 10000 2413 feb 24 12:10 README
|
|
||||||
-rw-r--r-- 1 fawkh 10000 43 feb 24 12:10 toaster-requirements.txt
|
|
||||||
-rw-r--r-- 1 fawkh 10000 2887 feb 24 12:10 TODO
|
|
||||||
|
|
||||||
At this point, you should have BitBake cloned to a directory that
|
|
||||||
matches the previous listing except for dates and user names.
|
|
||||||
|
|
||||||
Setting Up the BitBake Environment
|
|
||||||
==================================
|
|
||||||
|
|
||||||
First, you need to be sure that you can run BitBake. Set your working
|
|
||||||
directory to where your local BitBake files are and run the following
|
|
||||||
command::
|
|
||||||
|
|
||||||
$ ./bin/bitbake --version
|
|
||||||
BitBake Build Tool Core version 2.3.1
|
|
||||||
|
|
||||||
The console output tells you what version
|
|
||||||
you are running.
|
|
||||||
|
|
||||||
The recommended method to run BitBake is from a directory of your
|
|
||||||
choice. To be able to run BitBake from any directory, you need to add
|
|
||||||
the executable binary to your binary to your shell's environment
|
|
||||||
``PATH`` variable. First, look at your current ``PATH`` variable by
|
|
||||||
entering the following::
|
|
||||||
|
|
||||||
$ echo $PATH
|
|
||||||
|
|
||||||
Next, add the directory location
|
|
||||||
for the BitBake binary to the ``PATH``. Here is an example that adds the
|
|
||||||
``/home/scott-lenovo/bitbake/bin`` directory to the front of the
|
|
||||||
``PATH`` variable::
|
|
||||||
|
|
||||||
$ export PATH=/home/scott-lenovo/bitbake/bin:$PATH
|
|
||||||
|
|
||||||
You should now be able to enter the ``bitbake`` command from the command
|
|
||||||
line while working from any directory.
|
|
||||||
|
|
||||||
The Hello World Example
|
|
||||||
=======================
|
|
||||||
|
|
||||||
The overall goal of this exercise is to build a complete "Hello World"
|
|
||||||
example utilizing task and layer concepts. Because this is how modern
|
|
||||||
projects such as OpenEmbedded and the Yocto Project utilize BitBake, the
|
|
||||||
example provides an excellent starting point for understanding BitBake.
|
|
||||||
|
|
||||||
To help you understand how to use BitBake to build targets, the example
|
|
||||||
starts with nothing but the ``bitbake`` command, which causes BitBake to
|
|
||||||
fail and report problems. The example progresses by adding pieces to the
|
|
||||||
build to eventually conclude with a working, minimal "Hello World"
|
|
||||||
example.
|
|
||||||
|
|
||||||
While every attempt is made to explain what is happening during the
|
|
||||||
example, the descriptions cannot cover everything. You can find further
|
|
||||||
information throughout this manual. Also, you can actively participate
|
|
||||||
in the :oe_lists:`/g/bitbake-devel`
|
|
||||||
discussion mailing list about the BitBake build tool.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
This example was inspired by and drew heavily from
|
|
||||||
`Mailing List post - The BitBake equivalent of "Hello, World!"
|
|
||||||
<https://www.mail-archive.com/yocto@yoctoproject.org/msg09379.html>`_.
|
|
||||||
|
|
||||||
As stated earlier, the goal of this example is to eventually compile
|
|
||||||
"Hello World". However, it is unknown what BitBake needs and what you
|
|
||||||
have to provide in order to achieve that goal. Recall that BitBake
|
|
||||||
utilizes three types of metadata files:
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-intro:configuration files`,
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-intro:classes`, and
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-intro:recipes`.
|
|
||||||
But where do they go? How does BitBake find
|
|
||||||
them? BitBake's error messaging helps you answer these types of
|
|
||||||
questions and helps you better understand exactly what is going on.
|
|
||||||
|
|
||||||
Following is the complete "Hello World" example.
|
|
||||||
|
|
||||||
#. **Create a Project Directory:** First, set up a directory for the
|
|
||||||
"Hello World" project. Here is how you can do so in your home
|
|
||||||
directory::
|
|
||||||
|
|
||||||
$ mkdir ~/hello
|
|
||||||
$ cd ~/hello
|
|
||||||
|
|
||||||
This is the directory that
|
|
||||||
BitBake will use to do all of its work. You can use this directory
|
|
||||||
to keep all the metafiles needed by BitBake. Having a project
|
|
||||||
directory is a good way to isolate your project.
|
|
||||||
|
|
||||||
#. **Run BitBake:** At this point, you have nothing but a project
|
|
||||||
directory. Run the ``bitbake`` command and see what it does::
|
|
||||||
|
|
||||||
$ bitbake
|
|
||||||
ERROR: The BBPATH variable is not set and bitbake did not find a conf/bblayers.conf file in the expected location.
|
|
||||||
Maybe you accidentally invoked bitbake from the wrong directory?
|
|
||||||
|
|
||||||
When you run BitBake, it begins looking for metadata files. The
|
|
||||||
:term:`BBPATH` variable is what tells BitBake where
|
|
||||||
to look for those files. :term:`BBPATH` is not set and you need to set
|
|
||||||
it. Without :term:`BBPATH`, BitBake cannot find any configuration files
|
|
||||||
(``.conf``) or recipe files (``.bb``) at all. BitBake also cannot
|
|
||||||
find the ``bitbake.conf`` file.
|
|
||||||
|
|
||||||
#. **Setting BBPATH:** For this example, you can set :term:`BBPATH` in
|
|
||||||
the same manner that you set ``PATH`` earlier in the appendix. You
|
|
||||||
should realize, though, that it is much more flexible to set the
|
|
||||||
:term:`BBPATH` variable up in a configuration file for each project.
|
|
||||||
|
|
||||||
From your shell, enter the following commands to set and export the
|
|
||||||
:term:`BBPATH` variable::
|
|
||||||
|
|
||||||
$ BBPATH="projectdirectory"
|
|
||||||
$ export BBPATH
|
|
||||||
|
|
||||||
Use your actual project directory in the command. BitBake uses that
|
|
||||||
directory to find the metadata it needs for your project.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
When specifying your project directory, do not use the tilde
|
|
||||||
("~") character as BitBake does not expand that character as the
|
|
||||||
shell would.
|
|
||||||
|
|
||||||
#. **Run BitBake:** Now that you have :term:`BBPATH` defined, run the
|
|
||||||
``bitbake`` command again::
|
|
||||||
|
|
||||||
$ bitbake
|
|
||||||
ERROR: Unable to parse /home/scott-lenovo/bitbake/lib/bb/parse/__init__.py
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "/home/scott-lenovo/bitbake/lib/bb/parse/__init__.py", line 127, in resolve_file(fn='conf/bitbake.conf', d=<bb.data_smart.DataSmart object at 0x7f22919a3df0>):
|
|
||||||
if not newfn:
|
|
||||||
> raise IOError(errno.ENOENT, "file %s not found in %s" % (fn, bbpath))
|
|
||||||
fn = newfn
|
|
||||||
FileNotFoundError: [Errno 2] file conf/bitbake.conf not found in <projectdirectory>
|
|
||||||
|
|
||||||
|
|
||||||
This sample output shows that BitBake could not find the
|
|
||||||
``conf/bitbake.conf`` file in the project directory. This file is
|
|
||||||
the first thing BitBake must find in order to build a target. And,
|
|
||||||
since the project directory for this example is empty, you need to
|
|
||||||
provide a ``conf/bitbake.conf`` file.
|
|
||||||
|
|
||||||
#. **Creating conf/bitbake.conf:** The ``conf/bitbake.conf`` includes
|
|
||||||
a number of configuration variables BitBake uses for metadata and
|
|
||||||
recipe files. For this example, you need to create the file in your
|
|
||||||
project directory and define some key BitBake variables. For more
|
|
||||||
information on the ``bitbake.conf`` file, see
|
|
||||||
https://git.openembedded.org/bitbake/tree/conf/bitbake.conf.
|
|
||||||
|
|
||||||
Use the following commands to create the ``conf`` directory in the
|
|
||||||
project directory::
|
|
||||||
|
|
||||||
$ mkdir conf
|
|
||||||
|
|
||||||
From within the ``conf`` directory,
|
|
||||||
use some editor to create the ``bitbake.conf`` so that it contains
|
|
||||||
the following::
|
|
||||||
|
|
||||||
PN = "${@bb.parse.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
|
|
||||||
|
|
||||||
TMPDIR = "${TOPDIR}/tmp"
|
|
||||||
CACHE = "${TMPDIR}/cache"
|
|
||||||
STAMP = "${TMPDIR}/${PN}/stamps"
|
|
||||||
T = "${TMPDIR}/${PN}/work"
|
|
||||||
B = "${TMPDIR}/${PN}"
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Without a value for :term:`PN`, the variables :term:`STAMP`, :term:`T`, and :term:`B`, prevent more
|
|
||||||
than one recipe from working. You can fix this by either setting :term:`PN` to
|
|
||||||
have a value similar to what OpenEmbedded and BitBake use in the default
|
|
||||||
``bitbake.conf`` file (see previous example). Or, by manually updating each
|
|
||||||
recipe to set :term:`PN`. You will also need to include :term:`PN` as part of the :term:`STAMP`,
|
|
||||||
:term:`T`, and :term:`B` variable definitions in the ``local.conf`` file.
|
|
||||||
|
|
||||||
The ``TMPDIR`` variable establishes a directory that BitBake uses
|
|
||||||
for build output and intermediate files other than the cached
|
|
||||||
information used by the
|
|
||||||
:ref:`bitbake-user-manual/bitbake-user-manual-execution:setscene`
|
|
||||||
process. Here, the ``TMPDIR`` directory is set to ``hello/tmp``.
|
|
||||||
|
|
||||||
.. tip::
|
|
||||||
|
|
||||||
You can always safely delete the tmp directory in order to rebuild a
|
|
||||||
BitBake target. The build process creates the directory for you when you
|
|
||||||
run BitBake.
|
|
||||||
|
|
||||||
For information about each of the other variables defined in this
|
|
||||||
example, check :term:`PN`, :term:`TOPDIR`, :term:`CACHE`, :term:`STAMP`,
|
|
||||||
:term:`T` or :term:`B` to take you to the definitions in the
|
|
||||||
glossary.
|
|
||||||
|
|
||||||
#. **Run BitBake:** After making sure that the ``conf/bitbake.conf`` file
|
|
||||||
exists, you can run the ``bitbake`` command again::
|
|
||||||
|
|
||||||
$ bitbake
|
|
||||||
ERROR: Unable to parse /home/scott-lenovo/bitbake/lib/bb/parse/parse_py/BBHandler.py
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/BBHandler.py", line 67, in inherit(files=['base'], fn='configuration INHERITs', lineno=0, d=<bb.data_smart.DataSmart object at 0x7fab6815edf0>):
|
|
||||||
if not os.path.exists(file):
|
|
||||||
> raise ParseError("Could not inherit file %s" % (file), fn, lineno)
|
|
||||||
|
|
||||||
bb.parse.ParseError: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass
|
|
||||||
|
|
||||||
|
|
||||||
In the sample output,
|
|
||||||
BitBake could not find the ``classes/base.bbclass`` file. You need
|
|
||||||
to create that file next.
|
|
||||||
|
|
||||||
#. **Creating classes/base.bbclass:** BitBake uses class files to
|
|
||||||
provide common code and functionality. The minimally required class
|
|
||||||
for BitBake is the ``classes/base.bbclass`` file. The ``base`` class
|
|
||||||
is implicitly inherited by every recipe. BitBake looks for the class
|
|
||||||
in the ``classes`` directory of the project (i.e ``hello/classes``
|
|
||||||
in this example).
|
|
||||||
|
|
||||||
Create the ``classes`` directory as follows::
|
|
||||||
|
|
||||||
$ cd $HOME/hello
|
|
||||||
$ mkdir classes
|
|
||||||
|
|
||||||
Move to the ``classes`` directory and then create the
|
|
||||||
``base.bbclass`` file by inserting this single line::
|
|
||||||
|
|
||||||
addtask build
|
|
||||||
|
|
||||||
The minimal task that BitBake runs is the ``do_build`` task. This is
|
|
||||||
all the example needs in order to build the project. Of course, the
|
|
||||||
``base.bbclass`` can have much more depending on which build
|
|
||||||
environments BitBake is supporting.
|
|
||||||
|
|
||||||
#. **Run BitBake:** After making sure that the ``classes/base.bbclass``
|
|
||||||
file exists, you can run the ``bitbake`` command again::
|
|
||||||
|
|
||||||
$ bitbake
|
|
||||||
Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.
|
|
||||||
|
|
||||||
BitBake is finally reporting
|
|
||||||
no errors. However, you can see that it really does not have
|
|
||||||
anything to do. You need to create a recipe that gives BitBake
|
|
||||||
something to do.
|
|
||||||
|
|
||||||
#. **Creating a Layer:** While it is not really necessary for such a
|
|
||||||
small example, it is good practice to create a layer in which to
|
|
||||||
keep your code separate from the general metadata used by BitBake.
|
|
||||||
Thus, this example creates and uses a layer called "mylayer".
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
You can find additional information on layers in the
|
|
||||||
":ref:`bitbake-user-manual/bitbake-user-manual-intro:Layers`" section.
|
|
||||||
|
|
||||||
Minimally, you need a recipe file and a layer configuration file in
|
|
||||||
your layer. The configuration file needs to be in the ``conf``
|
|
||||||
directory inside the layer. Use these commands to set up the layer
|
|
||||||
and the ``conf`` directory::
|
|
||||||
|
|
||||||
$ cd $HOME
|
|
||||||
$ mkdir mylayer
|
|
||||||
$ cd mylayer
|
|
||||||
$ mkdir conf
|
|
||||||
|
|
||||||
Move to the ``conf`` directory and create a ``layer.conf`` file that has the
|
|
||||||
following::
|
|
||||||
|
|
||||||
BBPATH .= ":${LAYERDIR}"
|
|
||||||
BBFILES += "${LAYERDIR}/*.bb"
|
|
||||||
BBFILE_COLLECTIONS += "mylayer"
|
|
||||||
BBFILE_PATTERN_mylayer := "^${LAYERDIR_RE}/"
|
|
||||||
LAYERSERIES_CORENAMES = "hello_world_example"
|
|
||||||
LAYERSERIES_COMPAT_mylayer = "hello_world_example"
|
|
||||||
|
|
||||||
For information on these variables, click on :term:`BBFILES`,
|
|
||||||
:term:`LAYERDIR`, :term:`BBFILE_COLLECTIONS`, :term:`BBFILE_PATTERN_mylayer <BBFILE_PATTERN>`
|
|
||||||
or :term:`LAYERSERIES_COMPAT` to go to the definitions in the glossary.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
We are setting both ``LAYERSERIES_CORENAMES`` and :term:`LAYERSERIES_COMPAT` in this particular case, because we
|
|
||||||
are using bitbake without OpenEmbedded.
|
|
||||||
You should usually just use :term:`LAYERSERIES_COMPAT` to specify the OE-Core versions for which your layer
|
|
||||||
is compatible, and add the meta-openembedded layer to your project.
|
|
||||||
|
|
||||||
You need to create the recipe file next. Inside your layer at the
|
|
||||||
top-level, use an editor and create a recipe file named
|
|
||||||
``printhello.bb`` that has the following::
|
|
||||||
|
|
||||||
DESCRIPTION = "Prints Hello World"
|
|
||||||
PN = 'printhello'
|
|
||||||
PV = '1'
|
|
||||||
|
|
||||||
python do_build() {
|
|
||||||
bb.plain("********************");
|
|
||||||
bb.plain("* *");
|
|
||||||
bb.plain("* Hello, World! *");
|
|
||||||
bb.plain("* *");
|
|
||||||
bb.plain("********************");
|
|
||||||
}
|
|
||||||
|
|
||||||
The recipe file simply provides
|
|
||||||
a description of the recipe, the name, version, and the ``do_build``
|
|
||||||
task, which prints out "Hello World" to the console. For more
|
|
||||||
information on :term:`DESCRIPTION`, :term:`PN` or :term:`PV`
|
|
||||||
follow the links to the glossary.
|
|
||||||
|
|
||||||
#. **Run BitBake With a Target:** Now that a BitBake target exists, run
|
|
||||||
the command and provide that target::
|
|
||||||
|
|
||||||
$ cd $HOME/hello
|
|
||||||
$ bitbake printhello
|
|
||||||
ERROR: no recipe files to build, check your BBPATH and BBFILES?
|
|
||||||
|
|
||||||
Summary: There was 1 ERROR message shown, returning a non-zero exit code.
|
|
||||||
|
|
||||||
We have created the layer with the recipe and
|
|
||||||
the layer configuration file but it still seems that BitBake cannot
|
|
||||||
find the recipe. BitBake needs a ``conf/bblayers.conf`` that lists
|
|
||||||
the layers for the project. Without this file, BitBake cannot find
|
|
||||||
the recipe.
|
|
||||||
|
|
||||||
#. **Creating conf/bblayers.conf:** BitBake uses the
|
|
||||||
``conf/bblayers.conf`` file to locate layers needed for the project.
|
|
||||||
This file must reside in the ``conf`` directory of the project (i.e.
|
|
||||||
``hello/conf`` for this example).
|
|
||||||
|
|
||||||
Set your working directory to the ``hello/conf`` directory and then
|
|
||||||
create the ``bblayers.conf`` file so that it contains the following::
|
|
||||||
|
|
||||||
BBLAYERS ?= " \
|
|
||||||
/home/<you>/mylayer \
|
|
||||||
"
|
|
||||||
|
|
||||||
You need to provide your own information for ``you`` in the file.
|
|
||||||
|
|
||||||
#. **Run BitBake With a Target:** Now that you have supplied the
|
|
||||||
``bblayers.conf`` file, run the ``bitbake`` command and provide the
|
|
||||||
target::
|
|
||||||
|
|
||||||
$ bitbake printhello
|
|
||||||
Loading cache: 100% |
|
|
||||||
Loaded 0 entries from dependency cache.
|
|
||||||
Parsing recipes: 100% |##################################################################################|
|
|
||||||
Parsing of 1 .bb files complete (0 cached, 1 parsed). 1 targets, 0 skipped, 0 masked, 0 errors.
|
|
||||||
NOTE: Resolving any missing task queue dependencies
|
|
||||||
Initialising tasks: 100% |###############################################################################|
|
|
||||||
NOTE: No setscene tasks
|
|
||||||
NOTE: Executing Tasks
|
|
||||||
********************
|
|
||||||
* *
|
|
||||||
* Hello, World! *
|
|
||||||
* *
|
|
||||||
********************
|
|
||||||
NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
After the first execution, re-running bitbake printhello again will not
|
|
||||||
result in a BitBake run that prints the same console output. The reason
|
|
||||||
for this is that the first time the printhello.bb recipe's do_build task
|
|
||||||
executes successfully, BitBake writes a stamp file for the task. Thus,
|
|
||||||
the next time you attempt to run the task using that same bitbake
|
|
||||||
command, BitBake notices the stamp and therefore determines that the task
|
|
||||||
does not need to be re-run. If you delete the tmp directory or run
|
|
||||||
bitbake -c clean printhello and then re-run the build, the "Hello,
|
|
||||||
World!" message will be printed again.
|
|
||||||
513
bitbake/doc/bitbake-user-manual/bitbake-user-manual-hello.xml
Normal file
513
bitbake/doc/bitbake-user-manual/bitbake-user-manual-hello.xml
Normal file
@@ -0,0 +1,513 @@
|
|||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<appendix id='hello-world-example'>
|
||||||
|
<title>Hello World Example</title>
|
||||||
|
|
||||||
|
<section id='bitbake-hello-world'>
|
||||||
|
<title>BitBake Hello World</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The simplest example commonly used to demonstrate any new
|
||||||
|
programming language or tool is the
|
||||||
|
"<ulink url="http://en.wikipedia.org/wiki/Hello_world_program">Hello World</ulink>"
|
||||||
|
example.
|
||||||
|
This appendix demonstrates, in tutorial form, Hello
|
||||||
|
World within the context of BitBake.
|
||||||
|
The tutorial describes how to create a new project
|
||||||
|
and the applicable metadata files necessary to allow
|
||||||
|
BitBake to build it.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='example-obtaining-bitbake'>
|
||||||
|
<title>Obtaining BitBake</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
See the
|
||||||
|
"<link linkend='obtaining-bitbake'>Obtaining BitBake</link>"
|
||||||
|
section for information on how to obtain BitBake.
|
||||||
|
Once you have the source code on your machine, the BitBake directory
|
||||||
|
appears as follows:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ ls -al
|
||||||
|
total 100
|
||||||
|
drwxrwxr-x. 9 wmat wmat 4096 Jan 31 13:44 .
|
||||||
|
drwxrwxr-x. 3 wmat wmat 4096 Feb 4 10:45 ..
|
||||||
|
-rw-rw-r--. 1 wmat wmat 365 Nov 26 04:55 AUTHORS
|
||||||
|
drwxrwxr-x. 2 wmat wmat 4096 Nov 26 04:55 bin
|
||||||
|
drwxrwxr-x. 4 wmat wmat 4096 Jan 31 13:44 build
|
||||||
|
-rw-rw-r--. 1 wmat wmat 16501 Nov 26 04:55 ChangeLog
|
||||||
|
drwxrwxr-x. 2 wmat wmat 4096 Nov 26 04:55 classes
|
||||||
|
drwxrwxr-x. 2 wmat wmat 4096 Nov 26 04:55 conf
|
||||||
|
drwxrwxr-x. 3 wmat wmat 4096 Nov 26 04:55 contrib
|
||||||
|
-rw-rw-r--. 1 wmat wmat 17987 Nov 26 04:55 COPYING
|
||||||
|
drwxrwxr-x. 3 wmat wmat 4096 Nov 26 04:55 doc
|
||||||
|
-rw-rw-r--. 1 wmat wmat 69 Nov 26 04:55 .gitignore
|
||||||
|
-rw-rw-r--. 1 wmat wmat 849 Nov 26 04:55 HEADER
|
||||||
|
drwxrwxr-x. 5 wmat wmat 4096 Jan 31 13:44 lib
|
||||||
|
-rw-rw-r--. 1 wmat wmat 195 Nov 26 04:55 MANIFEST.in
|
||||||
|
-rw-rw-r--. 1 wmat wmat 2887 Nov 26 04:55 TODO
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
At this point, you should have BitBake cloned to
|
||||||
|
a directory that matches the previous listing except for
|
||||||
|
dates and user names.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='setting-up-the-bitbake-environment'>
|
||||||
|
<title>Setting Up the BitBake Environment</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
First, you need to be sure that you can run BitBake.
|
||||||
|
Set your working directory to where your local BitBake
|
||||||
|
files are and run the following command:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ ./bin/bitbake --version
|
||||||
|
BitBake Build Tool Core version 1.23.0, bitbake version 1.23.0
|
||||||
|
</literallayout>
|
||||||
|
The console output tells you what version you are running.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The recommended method to run BitBake is from a directory of your
|
||||||
|
choice.
|
||||||
|
To be able to run BitBake from any directory, you need to add the
|
||||||
|
executable binary to your binary to your shell's environment
|
||||||
|
<filename>PATH</filename> variable.
|
||||||
|
First, look at your current <filename>PATH</filename> variable
|
||||||
|
by entering the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ echo $PATH
|
||||||
|
</literallayout>
|
||||||
|
Next, add the directory location for the BitBake binary to the
|
||||||
|
<filename>PATH</filename>.
|
||||||
|
Here is an example that adds the
|
||||||
|
<filename>/home/scott-lenovo/bitbake/bin</filename> directory
|
||||||
|
to the front of the <filename>PATH</filename> variable:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ export PATH=/home/scott-lenovo/bitbake/bin:$PATH
|
||||||
|
</literallayout>
|
||||||
|
You should now be able to enter the <filename>bitbake</filename>
|
||||||
|
command from the command line while working from any directory.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='the-hello-world-example'>
|
||||||
|
<title>The Hello World Example</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The overall goal of this exercise is to build a
|
||||||
|
complete "Hello World" example utilizing task and layer
|
||||||
|
concepts.
|
||||||
|
Because this is how modern projects such as OpenEmbedded and
|
||||||
|
the Yocto Project utilize BitBake, the example
|
||||||
|
provides an excellent starting point for understanding
|
||||||
|
BitBake.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To help you understand how to use BitBake to build targets,
|
||||||
|
the example starts with nothing but the <filename>bitbake</filename>
|
||||||
|
command, which causes BitBake to fail and report problems.
|
||||||
|
The example progresses by adding pieces to the build to
|
||||||
|
eventually conclude with a working, minimal "Hello World"
|
||||||
|
example.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
While every attempt is made to explain what is happening during
|
||||||
|
the example, the descriptions cannot cover everything.
|
||||||
|
You can find further information throughout this manual.
|
||||||
|
Also, you can actively participate in the
|
||||||
|
<ulink url='http://lists.openembedded.org/mailman/listinfo/bitbake-devel'></ulink>
|
||||||
|
discussion mailing list about the BitBake build tool.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
This example was inspired by and drew heavily from
|
||||||
|
<ulink url="http://www.mail-archive.com/yocto@yoctoproject.org/msg09379.html">Mailing List post - The BitBake equivalent of "Hello, World!"</ulink>.
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As stated earlier, the goal of this example
|
||||||
|
is to eventually compile "Hello World".
|
||||||
|
However, it is unknown what BitBake needs and what you have
|
||||||
|
to provide in order to achieve that goal.
|
||||||
|
Recall that BitBake utilizes three types of metadata files:
|
||||||
|
<link linkend='configuration-files'>Configuration Files</link>,
|
||||||
|
<link linkend='classes'>Classes</link>, and
|
||||||
|
<link linkend='recipes'>Recipes</link>.
|
||||||
|
But where do they go?
|
||||||
|
How does BitBake find them?
|
||||||
|
BitBake's error messaging helps you answer these types of questions
|
||||||
|
and helps you better understand exactly what is going on.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Following is the complete "Hello World" example.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<orderedlist>
|
||||||
|
<listitem><para><emphasis>Create a Project Directory:</emphasis>
|
||||||
|
First, set up a directory for the "Hello World" project.
|
||||||
|
Here is how you can do so in your home directory:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ mkdir ~/hello
|
||||||
|
$ cd ~/hello
|
||||||
|
</literallayout>
|
||||||
|
This is the directory that BitBake will use to do all of
|
||||||
|
its work.
|
||||||
|
You can use this directory to keep all the metafiles needed
|
||||||
|
by BitBake.
|
||||||
|
Having a project directory is a good way to isolate your
|
||||||
|
project.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Run Bitbake:</emphasis>
|
||||||
|
At this point, you have nothing but a project directory.
|
||||||
|
Run the <filename>bitbake</filename> command and see what
|
||||||
|
it does:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake
|
||||||
|
The BBPATH variable is not set and bitbake did not
|
||||||
|
find a conf/bblayers.conf file in the expected location.
|
||||||
|
Maybe you accidentally invoked bitbake from the wrong directory?
|
||||||
|
DEBUG: Removed the following variables from the environment:
|
||||||
|
GNOME_DESKTOP_SESSION_ID, XDG_CURRENT_DESKTOP,
|
||||||
|
GNOME_KEYRING_CONTROL, DISPLAY, SSH_AGENT_PID, LANG, no_proxy,
|
||||||
|
XDG_SESSION_PATH, XAUTHORITY, SESSION_MANAGER, SHLVL,
|
||||||
|
MANDATORY_PATH, COMPIZ_CONFIG_PROFILE, WINDOWID, EDITOR,
|
||||||
|
GPG_AGENT_INFO, SSH_AUTH_SOCK, GDMSESSION, GNOME_KEYRING_PID,
|
||||||
|
XDG_SEAT_PATH, XDG_CONFIG_DIRS, LESSOPEN, DBUS_SESSION_BUS_ADDRESS,
|
||||||
|
_, XDG_SESSION_COOKIE, DESKTOP_SESSION, LESSCLOSE, DEFAULTS_PATH,
|
||||||
|
UBUNTU_MENUPROXY, OLDPWD, XDG_DATA_DIRS, COLORTERM, LS_COLORS
|
||||||
|
</literallayout>
|
||||||
|
The majority of this output is specific to environment variables
|
||||||
|
that are not directly relevant to BitBake.
|
||||||
|
However, the very first message regarding the
|
||||||
|
<filename>BBPATH</filename> variable and the
|
||||||
|
<filename>conf/bblayers.conf</filename> file
|
||||||
|
is relevant.</para>
|
||||||
|
<para>
|
||||||
|
When you run BitBake, it begins looking for metadata files.
|
||||||
|
The
|
||||||
|
<link linkend='var-bb-BBPATH'><filename>BBPATH</filename></link>
|
||||||
|
variable is what tells BitBake where to look for those files.
|
||||||
|
<filename>BBPATH</filename> is not set and you need to set it.
|
||||||
|
Without <filename>BBPATH</filename>, Bitbake cannot
|
||||||
|
find any configuration files (<filename>.conf</filename>)
|
||||||
|
or recipe files (<filename>.bb</filename>) at all.
|
||||||
|
BitBake also cannot find the <filename>bitbake.conf</filename>
|
||||||
|
file.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Setting <filename>BBPATH</filename>:</emphasis>
|
||||||
|
For this example, you can set <filename>BBPATH</filename>
|
||||||
|
in the same manner that you set <filename>PATH</filename>
|
||||||
|
earlier in the appendix.
|
||||||
|
You should realize, though, that it is much more flexible to set the
|
||||||
|
<filename>BBPATH</filename> variable up in a configuration
|
||||||
|
file for each project.</para>
|
||||||
|
<para>From your shell, enter the following commands to set and
|
||||||
|
export the <filename>BBPATH</filename> variable:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ BBPATH="<replaceable>projectdirectory</replaceable>"
|
||||||
|
$ export BBPATH
|
||||||
|
</literallayout>
|
||||||
|
Use your actual project directory in the command.
|
||||||
|
BitBake uses that directory to find the metadata it needs for
|
||||||
|
your project.
|
||||||
|
<note>
|
||||||
|
When specifying your project directory, do not use the
|
||||||
|
tilde ("~") character as BitBake does not expand that character
|
||||||
|
as the shell would.
|
||||||
|
</note>
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Run Bitbake:</emphasis>
|
||||||
|
Now that you have <filename>BBPATH</filename> defined, run
|
||||||
|
the <filename>bitbake</filename> command again:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake
|
||||||
|
ERROR: Traceback (most recent call last):
|
||||||
|
File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 163, in wrapped
|
||||||
|
return func(fn, *args)
|
||||||
|
File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 173, in parse_config_file
|
||||||
|
return bb.parse.handle(fn, data, include)
|
||||||
|
File "/home/scott-lenovo/bitbake/lib/bb/parse/__init__.py", line 99, in handle
|
||||||
|
return h['handle'](fn, data, include)
|
||||||
|
File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 120, in handle
|
||||||
|
abs_fn = resolve_file(fn, data)
|
||||||
|
File "/home/scott-lenovo/bitbake/lib/bb/parse/__init__.py", line 117, in resolve_file
|
||||||
|
raise IOError("file %s not found in %s" % (fn, bbpath))
|
||||||
|
IOError: file conf/bitbake.conf not found in /home/scott-lenovo/hello
|
||||||
|
|
||||||
|
ERROR: Unable to parse conf/bitbake.conf: file conf/bitbake.conf not found in /home/scott-lenovo/hello
|
||||||
|
</literallayout>
|
||||||
|
This sample output shows that BitBake could not find the
|
||||||
|
<filename>conf/bitbake.conf</filename> file in the project
|
||||||
|
directory.
|
||||||
|
This file is the first thing BitBake must find in order
|
||||||
|
to build a target.
|
||||||
|
And, since the project directory for this example is
|
||||||
|
empty, you need to provide a <filename>conf/bitbake.conf</filename>
|
||||||
|
file.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Creating <filename>conf/bitbake.conf</filename>:</emphasis>
|
||||||
|
The <filename>conf/bitbake.conf</filename> includes a number of
|
||||||
|
configuration variables BitBake uses for metadata and recipe
|
||||||
|
files.
|
||||||
|
For this example, you need to create the file in your project directory
|
||||||
|
and define some key BitBake variables.
|
||||||
|
For more information on the <filename>bitbake.conf</filename> file,
|
||||||
|
see
|
||||||
|
<ulink url='http://git.openembedded.org/bitbake/tree/conf/bitbake.conf'></ulink>.
|
||||||
|
</para>
|
||||||
|
<para>Use the following commands to create the <filename>conf</filename>
|
||||||
|
directory in the project directory:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ mkdir conf
|
||||||
|
</literallayout>
|
||||||
|
From within the <filename>conf</filename> directory, use
|
||||||
|
some editor to create the <filename>bitbake.conf</filename>
|
||||||
|
so that it contains the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
<link linkend='var-bb-PN'>PN</link> = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
|
||||||
|
</literallayout>
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
TMPDIR = "${<link linkend='var-bb-TOPDIR'>TOPDIR</link>}/tmp"
|
||||||
|
<link linkend='var-bb-CACHE'>CACHE</link> = "${TMPDIR}/cache"
|
||||||
|
<link linkend='var-bb-STAMP'>STAMP</link> = "${TMPDIR}/${PN}/stamps"
|
||||||
|
<link linkend='var-bb-T'>T</link> = "${TMPDIR}/${PN}/work"
|
||||||
|
<link linkend='var-bb-B'>B</link> = "${TMPDIR}/${PN}"
|
||||||
|
</literallayout>
|
||||||
|
<note>
|
||||||
|
Without a value for <filename>PN</filename>, the
|
||||||
|
variables <filename>STAMP</filename>,
|
||||||
|
<filename>T</filename>, and <filename>B</filename>,
|
||||||
|
prevent more than one recipe from working. You can fix
|
||||||
|
this by either setting <filename>PN</filename> to have
|
||||||
|
a value similar to what OpenEmbedded and BitBake use
|
||||||
|
in the default <filename>bitbake.conf</filename> file
|
||||||
|
(see previous example). Or, by manually updating each
|
||||||
|
recipe to set <filename>PN</filename>. You will also
|
||||||
|
need to include <filename>PN</filename> as part of the
|
||||||
|
<filename>STAMP</filename>, <filename>T</filename>, and
|
||||||
|
<filename>B</filename> variable definitions in the
|
||||||
|
<filename>local.conf</filename> file.
|
||||||
|
</note>
|
||||||
|
The <filename>TMPDIR</filename> variable establishes a directory
|
||||||
|
that BitBake uses for build output and intermediate files other
|
||||||
|
than the cached information used by the
|
||||||
|
<link linkend='setscene'>Setscene</link> process.
|
||||||
|
Here, the <filename>TMPDIR</filename> directory is set to
|
||||||
|
<filename>hello/tmp</filename>.
|
||||||
|
<note><title>Tip</title>
|
||||||
|
You can always safely delete the <filename>tmp</filename>
|
||||||
|
directory in order to rebuild a BitBake target.
|
||||||
|
The build process creates the directory for you
|
||||||
|
when you run BitBake.
|
||||||
|
</note></para>
|
||||||
|
<para>For information about each of the other variables defined in this
|
||||||
|
example, click on the links to take you to the definitions in
|
||||||
|
the glossary.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Run Bitbake:</emphasis>
|
||||||
|
After making sure that the <filename>conf/bitbake.conf</filename>
|
||||||
|
file exists, you can run the <filename>bitbake</filename>
|
||||||
|
command again:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake
|
||||||
|
ERROR: Traceback (most recent call last):
|
||||||
|
File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 163, in wrapped
|
||||||
|
return func(fn, *args)
|
||||||
|
File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 177, in _inherit
|
||||||
|
bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data)
|
||||||
|
File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/BBHandler.py", line 92, in inherit
|
||||||
|
include(fn, file, lineno, d, "inherit")
|
||||||
|
File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 100, in include
|
||||||
|
raise ParseError("Could not %(error_out)s file %(fn)s" % vars(), oldfn, lineno)
|
||||||
|
ParseError: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass
|
||||||
|
|
||||||
|
ERROR: Unable to parse base: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass
|
||||||
|
</literallayout>
|
||||||
|
In the sample output, BitBake could not find the
|
||||||
|
<filename>classes/base.bbclass</filename> file.
|
||||||
|
You need to create that file next.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Creating <filename>classes/base.bbclass</filename>:</emphasis>
|
||||||
|
BitBake uses class files to provide common code and functionality.
|
||||||
|
The minimally required class for BitBake is the
|
||||||
|
<filename>classes/base.bbclass</filename> file.
|
||||||
|
The <filename>base</filename> class is implicitly inherited by
|
||||||
|
every recipe.
|
||||||
|
BitBake looks for the class in the <filename>classes</filename>
|
||||||
|
directory of the project (i.e <filename>hello/classes</filename>
|
||||||
|
in this example).
|
||||||
|
</para>
|
||||||
|
<para>Create the <filename>classes</filename> directory as follows:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ cd $HOME/hello
|
||||||
|
$ mkdir classes
|
||||||
|
</literallayout>
|
||||||
|
Move to the <filename>classes</filename> directory and then
|
||||||
|
create the <filename>base.bbclass</filename> file by inserting
|
||||||
|
this single line:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
addtask build
|
||||||
|
</literallayout>
|
||||||
|
The minimal task that BitBake runs is the
|
||||||
|
<filename>do_build</filename> task.
|
||||||
|
This is all the example needs in order to build the project.
|
||||||
|
Of course, the <filename>base.bbclass</filename> can have much
|
||||||
|
more depending on which build environments BitBake is
|
||||||
|
supporting.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Run Bitbake:</emphasis>
|
||||||
|
After making sure that the <filename>classes/base.bbclass</filename>
|
||||||
|
file exists, you can run the <filename>bitbake</filename>
|
||||||
|
command again:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake
|
||||||
|
Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.
|
||||||
|
</literallayout>
|
||||||
|
BitBake is finally reporting no errors.
|
||||||
|
However, you can see that it really does not have anything
|
||||||
|
to do.
|
||||||
|
You need to create a recipe that gives BitBake something to do.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Creating a Layer:</emphasis>
|
||||||
|
While it is not really necessary for such a small example,
|
||||||
|
it is good practice to create a layer in which to keep your
|
||||||
|
code separate from the general metadata used by BitBake.
|
||||||
|
Thus, this example creates and uses a layer called "mylayer".
|
||||||
|
<note>
|
||||||
|
You can find additional information on layers in the
|
||||||
|
"<link linkend='layers'>Layers</link>" section.
|
||||||
|
</note></para>
|
||||||
|
|
||||||
|
<para>Minimally, you need a recipe file and a layer configuration
|
||||||
|
file in your layer.
|
||||||
|
The configuration file needs to be in the <filename>conf</filename>
|
||||||
|
directory inside the layer.
|
||||||
|
Use these commands to set up the layer and the <filename>conf</filename>
|
||||||
|
directory:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ cd $HOME
|
||||||
|
$ mkdir mylayer
|
||||||
|
$ cd mylayer
|
||||||
|
$ mkdir conf
|
||||||
|
</literallayout>
|
||||||
|
Move to the <filename>conf</filename> directory and create a
|
||||||
|
<filename>layer.conf</filename> file that has the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
BBPATH .= ":${<link linkend='var-bb-LAYERDIR'>LAYERDIR</link>}"
|
||||||
|
|
||||||
|
<link linkend='var-bb-BBFILES'>BBFILES</link> += "${LAYERDIR}/*.bb"
|
||||||
|
|
||||||
|
<link linkend='var-bb-BBFILE_COLLECTIONS'>BBFILE_COLLECTIONS</link> += "mylayer"
|
||||||
|
<link linkend='var-bb-BBFILE_PATTERN'>BBFILE_PATTERN_mylayer</link> := "^${LAYERDIR_RE}/"
|
||||||
|
</literallayout>
|
||||||
|
For information on these variables, click the links
|
||||||
|
to go to the definitions in the glossary.</para>
|
||||||
|
<para>You need to create the recipe file next.
|
||||||
|
Inside your layer at the top-level, use an editor and create
|
||||||
|
a recipe file named <filename>printhello.bb</filename> that
|
||||||
|
has the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
<link linkend='var-bb-DESCRIPTION'>DESCRIPTION</link> = "Prints Hello World"
|
||||||
|
<link linkend='var-bb-PN'>PN</link> = 'printhello'
|
||||||
|
<link linkend='var-bb-PV'>PV</link> = '1'
|
||||||
|
|
||||||
|
python do_build() {
|
||||||
|
bb.plain("********************");
|
||||||
|
bb.plain("* *");
|
||||||
|
bb.plain("* Hello, World! *");
|
||||||
|
bb.plain("* *");
|
||||||
|
bb.plain("********************");
|
||||||
|
}
|
||||||
|
</literallayout>
|
||||||
|
The recipe file simply provides a description of the
|
||||||
|
recipe, the name, version, and the <filename>do_build</filename>
|
||||||
|
task, which prints out "Hello World" to the console.
|
||||||
|
For more information on these variables, follow the links
|
||||||
|
to the glossary.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Run Bitbake With a Target:</emphasis>
|
||||||
|
Now that a BitBake target exists, run the command and provide
|
||||||
|
that target:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ cd $HOME/hello
|
||||||
|
$ bitbake printhello
|
||||||
|
ERROR: no recipe files to build, check your BBPATH and BBFILES?
|
||||||
|
|
||||||
|
Summary: There was 1 ERROR message shown, returning a non-zero exit code.
|
||||||
|
</literallayout>
|
||||||
|
We have created the layer with the recipe and the layer
|
||||||
|
configuration file but it still seems that BitBake cannot
|
||||||
|
find the recipe.
|
||||||
|
BitBake needs a <filename>conf/bblayers.conf</filename> that
|
||||||
|
lists the layers for the project.
|
||||||
|
Without this file, BitBake cannot find the recipe.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Creating <filename>conf/bblayers.conf</filename>:</emphasis>
|
||||||
|
BitBake uses the <filename>conf/bblayers.conf</filename> file
|
||||||
|
to locate layers needed for the project.
|
||||||
|
This file must reside in the <filename>conf</filename> directory
|
||||||
|
of the project (i.e. <filename>hello/conf</filename> for this
|
||||||
|
example).</para>
|
||||||
|
<para>Set your working directory to the <filename>hello/conf</filename>
|
||||||
|
directory and then create the <filename>bblayers.conf</filename>
|
||||||
|
file so that it contains the following:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
BBLAYERS ?= " \
|
||||||
|
/home/<you>/mylayer \
|
||||||
|
"
|
||||||
|
</literallayout>
|
||||||
|
You need to provide your own information for
|
||||||
|
<filename>you</filename> in the file.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Run Bitbake With a Target:</emphasis>
|
||||||
|
Now that you have supplied the <filename>bblayers.conf</filename>
|
||||||
|
file, run the <filename>bitbake</filename> command and provide
|
||||||
|
the target:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake printhello
|
||||||
|
Parsing recipes: 100% |##################################################################################|
|
||||||
|
Time: 00:00:00
|
||||||
|
Parsing of 1 .bb files complete (0 cached, 1 parsed). 1 targets, 0 skipped, 0 masked, 0 errors.
|
||||||
|
NOTE: Resolving any missing task queue dependencies
|
||||||
|
NOTE: Preparing RunQueue
|
||||||
|
NOTE: Executing RunQueue Tasks
|
||||||
|
********************
|
||||||
|
* *
|
||||||
|
* Hello, World! *
|
||||||
|
* *
|
||||||
|
********************
|
||||||
|
NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded.
|
||||||
|
</literallayout>
|
||||||
|
BitBake finds the <filename>printhello</filename> recipe and
|
||||||
|
successfully runs the task.
|
||||||
|
<note>
|
||||||
|
After the first execution, re-running
|
||||||
|
<filename>bitbake printhello</filename> again will not
|
||||||
|
result in a BitBake run that prints the same console
|
||||||
|
output.
|
||||||
|
The reason for this is that the first time the
|
||||||
|
<filename>printhello.bb</filename> recipe's
|
||||||
|
<filename>do_build</filename> task executes
|
||||||
|
successfully, BitBake writes a stamp file for the task.
|
||||||
|
Thus, the next time you attempt to run the task
|
||||||
|
using that same <filename>bitbake</filename> command,
|
||||||
|
BitBake notices the stamp and therefore determines
|
||||||
|
that the task does not need to be re-run.
|
||||||
|
If you delete the <filename>tmp</filename> directory
|
||||||
|
or run <filename>bitbake -c clean printhello</filename>
|
||||||
|
and then re-run the build, the "Hello, World!" message will
|
||||||
|
be printed again.
|
||||||
|
</note>
|
||||||
|
</para></listitem>
|
||||||
|
</orderedlist>
|
||||||
|
</section>
|
||||||
|
</appendix>
|
||||||
@@ -1,653 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: CC-BY-2.5
|
|
||||||
|
|
||||||
========
|
|
||||||
Overview
|
|
||||||
========
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
Welcome to the BitBake User Manual. This manual provides information on
|
|
||||||
the BitBake tool. The information attempts to be as independent as
|
|
||||||
possible regarding systems that use BitBake, such as OpenEmbedded and
|
|
||||||
the Yocto Project. In some cases, scenarios or examples within the
|
|
||||||
context of a build system are used in the manual to help with
|
|
||||||
understanding. For these cases, the manual clearly states the context.
|
|
||||||
|
|
||||||
.. _intro:
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
============
|
|
||||||
|
|
||||||
Fundamentally, BitBake is a generic task execution engine that allows
|
|
||||||
shell and Python tasks to be run efficiently and in parallel while
|
|
||||||
working within complex inter-task dependency constraints. One of
|
|
||||||
BitBake's main users, OpenEmbedded, takes this core and builds embedded
|
|
||||||
Linux software stacks using a task-oriented approach.
|
|
||||||
|
|
||||||
Conceptually, BitBake is similar to GNU Make in some regards but has
|
|
||||||
significant differences:
|
|
||||||
|
|
||||||
- BitBake executes tasks according to the provided metadata that builds up
|
|
||||||
the tasks. Metadata is stored in recipe (``.bb``) and related recipe
|
|
||||||
"append" (``.bbappend``) files, configuration (``.conf``) and
|
|
||||||
underlying include (``.inc``) files, and in class (``.bbclass``)
|
|
||||||
files. The metadata provides BitBake with instructions on what tasks
|
|
||||||
to run and the dependencies between those tasks.
|
|
||||||
|
|
||||||
- BitBake includes a fetcher library for obtaining source code from
|
|
||||||
various places such as local files, source control systems, or
|
|
||||||
websites.
|
|
||||||
|
|
||||||
- The instructions for each unit to be built (e.g. a piece of software)
|
|
||||||
are known as "recipe" files and contain all the information about the
|
|
||||||
unit (dependencies, source file locations, checksums, description and
|
|
||||||
so on).
|
|
||||||
|
|
||||||
- BitBake includes a client/server abstraction and can be used from a
|
|
||||||
command line or used as a service over XML-RPC and has several
|
|
||||||
different user interfaces.
|
|
||||||
|
|
||||||
History and Goals
|
|
||||||
=================
|
|
||||||
|
|
||||||
BitBake was originally a part of the OpenEmbedded project. It was
|
|
||||||
inspired by the Portage package management system used by the Gentoo
|
|
||||||
Linux distribution. On December 7, 2004, OpenEmbedded project team
|
|
||||||
member Chris Larson split the project into two distinct pieces:
|
|
||||||
|
|
||||||
- BitBake, a generic task executor
|
|
||||||
|
|
||||||
- OpenEmbedded, a metadata set utilized by BitBake
|
|
||||||
|
|
||||||
Today, BitBake is the primary basis of the
|
|
||||||
`OpenEmbedded <https://www.openembedded.org/>`__ project, which is being
|
|
||||||
used to build and maintain Linux distributions such as the `Poky
|
|
||||||
Reference Distribution <https://www.yoctoproject.org/software-item/poky/>`__,
|
|
||||||
developed under the umbrella of the `Yocto Project <https://www.yoctoproject.org>`__.
|
|
||||||
|
|
||||||
Prior to BitBake, no other build tool adequately met the needs of an
|
|
||||||
aspiring embedded Linux distribution. All of the build systems used by
|
|
||||||
traditional desktop Linux distributions lacked important functionality,
|
|
||||||
and none of the ad hoc Buildroot-based systems, prevalent in the
|
|
||||||
embedded space, were scalable or maintainable.
|
|
||||||
|
|
||||||
Some important original goals for BitBake were:
|
|
||||||
|
|
||||||
- Handle cross-compilation.
|
|
||||||
|
|
||||||
- Handle inter-package dependencies (build time on target architecture,
|
|
||||||
build time on native architecture, and runtime).
|
|
||||||
|
|
||||||
- Support running any number of tasks within a given package,
|
|
||||||
including, but not limited to, fetching upstream sources, unpacking
|
|
||||||
them, patching them, configuring them, and so forth.
|
|
||||||
|
|
||||||
- Be Linux distribution agnostic for both build and target systems.
|
|
||||||
|
|
||||||
- Be architecture agnostic.
|
|
||||||
|
|
||||||
- Support multiple build and target operating systems (e.g. Cygwin, the
|
|
||||||
BSDs, and so forth).
|
|
||||||
|
|
||||||
- Be self-contained, rather than tightly integrated into the build
|
|
||||||
machine's root filesystem.
|
|
||||||
|
|
||||||
- Handle conditional metadata on the target architecture, operating
|
|
||||||
system, distribution, and machine.
|
|
||||||
|
|
||||||
- Be easy to use the tools to supply local metadata and packages
|
|
||||||
against which to operate.
|
|
||||||
|
|
||||||
- Be easy to use BitBake to collaborate between multiple projects for
|
|
||||||
their builds.
|
|
||||||
|
|
||||||
- Provide an inheritance mechanism to share common metadata between
|
|
||||||
many packages.
|
|
||||||
|
|
||||||
Over time it became apparent that some further requirements were
|
|
||||||
necessary:
|
|
||||||
|
|
||||||
- Handle variants of a base recipe (e.g. native, sdk, and multilib).
|
|
||||||
|
|
||||||
- Split metadata into layers and allow layers to enhance or override
|
|
||||||
other layers.
|
|
||||||
|
|
||||||
- Allow representation of a given set of input variables to a task as a
|
|
||||||
checksum. Based on that checksum, allow acceleration of builds with
|
|
||||||
prebuilt components.
|
|
||||||
|
|
||||||
BitBake satisfies all the original requirements and many more with
|
|
||||||
extensions being made to the basic functionality to reflect the
|
|
||||||
additional requirements. Flexibility and power have always been the
|
|
||||||
priorities. BitBake is highly extensible and supports embedded Python
|
|
||||||
code and execution of any arbitrary tasks.
|
|
||||||
|
|
||||||
.. _Concepts:
|
|
||||||
|
|
||||||
Concepts
|
|
||||||
========
|
|
||||||
|
|
||||||
BitBake is a program written in the Python language. At the highest
|
|
||||||
level, BitBake interprets metadata, decides what tasks are required to
|
|
||||||
run, and executes those tasks. Similar to GNU Make, BitBake controls how
|
|
||||||
software is built. GNU Make achieves its control through "makefiles",
|
|
||||||
while BitBake uses "recipes".
|
|
||||||
|
|
||||||
BitBake extends the capabilities of a simple tool like GNU Make by
|
|
||||||
allowing for the definition of much more complex tasks, such as
|
|
||||||
assembling entire embedded Linux distributions.
|
|
||||||
|
|
||||||
The remainder of this section introduces several concepts that should be
|
|
||||||
understood in order to better leverage the power of BitBake.
|
|
||||||
|
|
||||||
Recipes
|
|
||||||
-------
|
|
||||||
|
|
||||||
BitBake Recipes, which are denoted by the file extension ``.bb``, are
|
|
||||||
the most basic metadata files. These recipe files provide BitBake with
|
|
||||||
the following:
|
|
||||||
|
|
||||||
- Descriptive information about the package (author, homepage, license,
|
|
||||||
and so on)
|
|
||||||
|
|
||||||
- The version of the recipe
|
|
||||||
|
|
||||||
- Existing dependencies (both build and runtime dependencies)
|
|
||||||
|
|
||||||
- Where the source code resides and how to fetch it
|
|
||||||
|
|
||||||
- Whether the source code requires any patches, where to find them, and
|
|
||||||
how to apply them
|
|
||||||
|
|
||||||
- How to configure and compile the source code
|
|
||||||
|
|
||||||
- How to assemble the generated artifacts into one or more installable
|
|
||||||
packages
|
|
||||||
|
|
||||||
- Where on the target machine to install the package or packages
|
|
||||||
created
|
|
||||||
|
|
||||||
Within the context of BitBake, or any project utilizing BitBake as its
|
|
||||||
build system, files with the ``.bb`` extension are referred to as
|
|
||||||
recipes.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
The term "package" is also commonly used to describe recipes.
|
|
||||||
However, since the same word is used to describe packaged output from
|
|
||||||
a project, it is best to maintain a single descriptive term -
|
|
||||||
"recipes". Put another way, a single "recipe" file is quite capable
|
|
||||||
of generating a number of related but separately installable
|
|
||||||
"packages". In fact, that ability is fairly common.
|
|
||||||
|
|
||||||
Configuration Files
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
Configuration files, which are denoted by the ``.conf`` extension,
|
|
||||||
define various configuration variables that govern the project's build
|
|
||||||
process. These files fall into several areas that define machine
|
|
||||||
configuration, distribution configuration, possible compiler tuning,
|
|
||||||
general common configuration, and user configuration. The main
|
|
||||||
configuration file is the sample ``bitbake.conf`` file, which is located
|
|
||||||
within the BitBake source tree ``conf`` directory.
|
|
||||||
|
|
||||||
Classes
|
|
||||||
-------
|
|
||||||
|
|
||||||
Class files, which are denoted by the ``.bbclass`` extension, contain
|
|
||||||
information that is useful to share between metadata files. The BitBake
|
|
||||||
source tree currently comes with one class metadata file called
|
|
||||||
``base.bbclass``. You can find this file in the ``classes`` directory.
|
|
||||||
The ``base.bbclass`` class files is special since it is always included
|
|
||||||
automatically for all recipes and classes. This class contains
|
|
||||||
definitions for standard basic tasks such as fetching, unpacking,
|
|
||||||
configuring (empty by default), compiling (runs any Makefile present),
|
|
||||||
installing (empty by default) and packaging (empty by default). These
|
|
||||||
tasks are often overridden or extended by other classes added during the
|
|
||||||
project development process.
|
|
||||||
|
|
||||||
Layers
|
|
||||||
------
|
|
||||||
|
|
||||||
Layers allow you to isolate different types of customizations from each
|
|
||||||
other. While you might find it tempting to keep everything in one layer
|
|
||||||
when working on a single project, the more modular your metadata, the
|
|
||||||
easier it is to cope with future changes.
|
|
||||||
|
|
||||||
To illustrate how you can use layers to keep things modular, consider
|
|
||||||
customizations you might make to support a specific target machine.
|
|
||||||
These types of customizations typically reside in a special layer,
|
|
||||||
rather than a general layer, called a Board Support Package (BSP) layer.
|
|
||||||
Furthermore, the machine customizations should be isolated from recipes
|
|
||||||
and metadata that support a new GUI environment, for example. This
|
|
||||||
situation gives you a couple of layers: one for the machine
|
|
||||||
configurations and one for the GUI environment. It is important to
|
|
||||||
understand, however, that the BSP layer can still make machine-specific
|
|
||||||
additions to recipes within the GUI environment layer without polluting
|
|
||||||
the GUI layer itself with those machine-specific changes. You can
|
|
||||||
accomplish this through a recipe that is a BitBake append
|
|
||||||
(``.bbappend``) file.
|
|
||||||
|
|
||||||
.. _append-bbappend-files:
|
|
||||||
|
|
||||||
Append Files
|
|
||||||
------------
|
|
||||||
|
|
||||||
Append files, which are files that have the ``.bbappend`` file
|
|
||||||
extension, extend or override information in an existing recipe file.
|
|
||||||
|
|
||||||
BitBake expects every append file to have a corresponding recipe file.
|
|
||||||
Furthermore, the append file and corresponding recipe file must use the
|
|
||||||
same root filename. The filenames can differ only in the file type
|
|
||||||
suffix used (e.g. ``formfactor_0.0.bb`` and
|
|
||||||
``formfactor_0.0.bbappend``).
|
|
||||||
|
|
||||||
Information in append files extends or overrides the information in the
|
|
||||||
underlying, similarly-named recipe files.
|
|
||||||
|
|
||||||
When you name an append file, you can use the "``%``" wildcard character
|
|
||||||
to allow for matching recipe names. For example, suppose you have an
|
|
||||||
append file named as follows::
|
|
||||||
|
|
||||||
busybox_1.21.%.bbappend
|
|
||||||
|
|
||||||
That append file
|
|
||||||
would match any ``busybox_1.21.``\ x\ ``.bb`` version of the recipe. So,
|
|
||||||
the append file would match the following recipe names::
|
|
||||||
|
|
||||||
busybox_1.21.1.bb
|
|
||||||
busybox_1.21.2.bb
|
|
||||||
busybox_1.21.3.bb
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
The use of the " % " character is limited in that it only works directly in
|
|
||||||
front of the .bbappend portion of the append file's name. You cannot use the
|
|
||||||
wildcard character in any other location of the name.
|
|
||||||
|
|
||||||
If the ``busybox`` recipe was updated to ``busybox_1.3.0.bb``, the
|
|
||||||
append name would not match. However, if you named the append file
|
|
||||||
``busybox_1.%.bbappend``, then you would have a match.
|
|
||||||
|
|
||||||
In the most general case, you could name the append file something as
|
|
||||||
simple as ``busybox_%.bbappend`` to be entirely version independent.
|
|
||||||
|
|
||||||
Obtaining BitBake
|
|
||||||
=================
|
|
||||||
|
|
||||||
You can obtain BitBake several different ways:
|
|
||||||
|
|
||||||
- **Cloning BitBake:** Using Git to clone the BitBake source code
|
|
||||||
repository is the recommended method for obtaining BitBake. Cloning
|
|
||||||
the repository makes it easy to get bug fixes and have access to
|
|
||||||
stable branches and the master branch. Once you have cloned BitBake,
|
|
||||||
you should use the latest stable branch for development since the
|
|
||||||
master branch is for BitBake development and might contain less
|
|
||||||
stable changes.
|
|
||||||
|
|
||||||
You usually need a version of BitBake that matches the metadata you
|
|
||||||
are using. The metadata is generally backwards compatible but not
|
|
||||||
forward compatible.
|
|
||||||
|
|
||||||
Here is an example that clones the BitBake repository::
|
|
||||||
|
|
||||||
$ git clone git://git.openembedded.org/bitbake
|
|
||||||
|
|
||||||
This command clones the BitBake
|
|
||||||
Git repository into a directory called ``bitbake``. Alternatively,
|
|
||||||
you can designate a directory after the ``git clone`` command if you
|
|
||||||
want to call the new directory something other than ``bitbake``. Here
|
|
||||||
is an example that names the directory ``bbdev``::
|
|
||||||
|
|
||||||
$ git clone git://git.openembedded.org/bitbake bbdev
|
|
||||||
|
|
||||||
- **Installation using your Distribution Package Management System:**
|
|
||||||
This method is not recommended because the BitBake version that is
|
|
||||||
provided by your distribution, in most cases, is several releases
|
|
||||||
behind a snapshot of the BitBake repository.
|
|
||||||
|
|
||||||
- **Taking a snapshot of BitBake:** Downloading a snapshot of BitBake
|
|
||||||
from the source code repository gives you access to a known branch or
|
|
||||||
release of BitBake.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Cloning the Git repository, as described earlier, is the preferred
|
|
||||||
method for getting BitBake. Cloning the repository makes it easier
|
|
||||||
to update as patches are added to the stable branches.
|
|
||||||
|
|
||||||
The following example downloads a snapshot of BitBake version 1.17.0::
|
|
||||||
|
|
||||||
$ wget https://git.openembedded.org/bitbake/snapshot/bitbake-1.17.0.tar.gz
|
|
||||||
$ tar zxpvf bitbake-1.17.0.tar.gz
|
|
||||||
|
|
||||||
After extraction of the tarball using
|
|
||||||
the tar utility, you have a directory entitled ``bitbake-1.17.0``.
|
|
||||||
|
|
||||||
- **Using the BitBake that Comes With Your Build Checkout:** A final
|
|
||||||
possibility for getting a copy of BitBake is that it already comes
|
|
||||||
with your checkout of a larger BitBake-based build system, such as
|
|
||||||
Poky. Rather than manually checking out individual layers and gluing
|
|
||||||
them together yourself, you can check out an entire build system. The
|
|
||||||
checkout will already include a version of BitBake that has been
|
|
||||||
thoroughly tested for compatibility with the other components. For
|
|
||||||
information on how to check out a particular BitBake-based build
|
|
||||||
system, consult that build system's supporting documentation.
|
|
||||||
|
|
||||||
.. _bitbake-user-manual-command:
|
|
||||||
|
|
||||||
The BitBake Command
|
|
||||||
===================
|
|
||||||
|
|
||||||
The ``bitbake`` command is the primary interface to the BitBake tool.
|
|
||||||
This section presents the BitBake command syntax and provides several
|
|
||||||
execution examples.
|
|
||||||
|
|
||||||
Usage and syntax
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Following is the usage and syntax for BitBake::
|
|
||||||
|
|
||||||
$ bitbake -h
|
|
||||||
Usage: bitbake [options] [recipename/target recipe:do_task ...]
|
|
||||||
|
|
||||||
Executes the specified task (default is 'build') for a given set of target recipes (.bb files).
|
|
||||||
It is assumed there is a conf/bblayers.conf available in cwd or in BBPATH which
|
|
||||||
will provide the layer, BBFILES and other configuration information.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--version show program's version number and exit
|
|
||||||
-h, --help show this help message and exit
|
|
||||||
-b BUILDFILE, --buildfile=BUILDFILE
|
|
||||||
Execute tasks from a specific .bb recipe directly.
|
|
||||||
WARNING: Does not handle any dependencies from other
|
|
||||||
recipes.
|
|
||||||
-k, --continue Continue as much as possible after an error. While the
|
|
||||||
target that failed and anything depending on it cannot
|
|
||||||
be built, as much as possible will be built before
|
|
||||||
stopping.
|
|
||||||
-f, --force Force the specified targets/task to run (invalidating
|
|
||||||
any existing stamp file).
|
|
||||||
-c CMD, --cmd=CMD Specify the task to execute. The exact options
|
|
||||||
available depend on the metadata. Some examples might
|
|
||||||
be 'compile' or 'populate_sysroot' or 'listtasks' may
|
|
||||||
give a list of the tasks available.
|
|
||||||
-C INVALIDATE_STAMP, --clear-stamp=INVALIDATE_STAMP
|
|
||||||
Invalidate the stamp for the specified task such as
|
|
||||||
'compile' and then run the default task for the
|
|
||||||
specified target(s).
|
|
||||||
-r PREFILE, --read=PREFILE
|
|
||||||
Read the specified file before bitbake.conf.
|
|
||||||
-R POSTFILE, --postread=POSTFILE
|
|
||||||
Read the specified file after bitbake.conf.
|
|
||||||
-v, --verbose Enable tracing of shell tasks (with 'set -x'). Also
|
|
||||||
print bb.note(...) messages to stdout (in addition to
|
|
||||||
writing them to ${T}/log.do_<task>).
|
|
||||||
-D, --debug Increase the debug level. You can specify this more
|
|
||||||
than once. -D sets the debug level to 1, where only
|
|
||||||
bb.debug(1, ...) messages are printed to stdout; -DD
|
|
||||||
sets the debug level to 2, where both bb.debug(1, ...)
|
|
||||||
and bb.debug(2, ...) messages are printed; etc.
|
|
||||||
Without -D, no debug messages are printed. Note that
|
|
||||||
-D only affects output to stdout. All debug messages
|
|
||||||
are written to ${T}/log.do_taskname, regardless of the
|
|
||||||
debug level.
|
|
||||||
-q, --quiet Output less log message data to the terminal. You can
|
|
||||||
specify this more than once.
|
|
||||||
-n, --dry-run Don't execute, just go through the motions.
|
|
||||||
-S SIGNATURE_HANDLER, --dump-signatures=SIGNATURE_HANDLER
|
|
||||||
Dump out the signature construction information, with
|
|
||||||
no task execution. The SIGNATURE_HANDLER parameter is
|
|
||||||
passed to the handler. Two common values are none and
|
|
||||||
printdiff but the handler may define more/less. none
|
|
||||||
means only dump the signature, printdiff means compare
|
|
||||||
the dumped signature with the cached one.
|
|
||||||
-p, --parse-only Quit after parsing the BB recipes.
|
|
||||||
-s, --show-versions Show current and preferred versions of all recipes.
|
|
||||||
-e, --environment Show the global or per-recipe environment complete
|
|
||||||
with information about where variables were
|
|
||||||
set/changed.
|
|
||||||
-g, --graphviz Save dependency tree information for the specified
|
|
||||||
targets in the dot syntax.
|
|
||||||
-I EXTRA_ASSUME_PROVIDED, --ignore-deps=EXTRA_ASSUME_PROVIDED
|
|
||||||
Assume these dependencies don't exist and are already
|
|
||||||
provided (equivalent to ASSUME_PROVIDED). Useful to
|
|
||||||
make dependency graphs more appealing
|
|
||||||
-l DEBUG_DOMAINS, --log-domains=DEBUG_DOMAINS
|
|
||||||
Show debug logging for the specified logging domains
|
|
||||||
-P, --profile Profile the command and save reports.
|
|
||||||
-u UI, --ui=UI The user interface to use (knotty, ncurses, taskexp or
|
|
||||||
teamcity - default knotty).
|
|
||||||
--token=XMLRPCTOKEN Specify the connection token to be used when
|
|
||||||
connecting to a remote server.
|
|
||||||
--revisions-changed Set the exit code depending on whether upstream
|
|
||||||
floating revisions have changed or not.
|
|
||||||
--server-only Run bitbake without a UI, only starting a server
|
|
||||||
(cooker) process.
|
|
||||||
-B BIND, --bind=BIND The name/address for the bitbake xmlrpc server to bind
|
|
||||||
to.
|
|
||||||
-T SERVER_TIMEOUT, --idle-timeout=SERVER_TIMEOUT
|
|
||||||
Set timeout to unload bitbake server due to
|
|
||||||
inactivity, set to -1 means no unload, default:
|
|
||||||
Environment variable BB_SERVER_TIMEOUT.
|
|
||||||
--no-setscene Do not run any setscene tasks. sstate will be ignored
|
|
||||||
and everything needed, built.
|
|
||||||
--skip-setscene Skip setscene tasks if they would be executed. Tasks
|
|
||||||
previously restored from sstate will be kept, unlike
|
|
||||||
--no-setscene
|
|
||||||
--setscene-only Only run setscene tasks, don't run any real tasks.
|
|
||||||
--remote-server=REMOTE_SERVER
|
|
||||||
Connect to the specified server.
|
|
||||||
-m, --kill-server Terminate any running bitbake server.
|
|
||||||
--observe-only Connect to a server as an observing-only client.
|
|
||||||
--status-only Check the status of the remote bitbake server.
|
|
||||||
-w WRITEEVENTLOG, --write-log=WRITEEVENTLOG
|
|
||||||
Writes the event log of the build to a bitbake event
|
|
||||||
json file. Use '' (empty string) to assign the name
|
|
||||||
automatically.
|
|
||||||
--runall=RUNALL Run the specified task for any recipe in the taskgraph
|
|
||||||
of the specified target (even if it wouldn't otherwise
|
|
||||||
have run).
|
|
||||||
--runonly=RUNONLY Run only the specified task within the taskgraph of
|
|
||||||
the specified targets (and any task dependencies those
|
|
||||||
tasks may have).
|
|
||||||
|
|
||||||
.. _bitbake-examples:
|
|
||||||
|
|
||||||
Examples
|
|
||||||
--------
|
|
||||||
|
|
||||||
This section presents some examples showing how to use BitBake.
|
|
||||||
|
|
||||||
.. _example-executing-a-task-against-a-single-recipe:
|
|
||||||
|
|
||||||
Executing a Task Against a Single Recipe
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Executing tasks for a single recipe file is relatively simple. You
|
|
||||||
specify the file in question, and BitBake parses it and executes the
|
|
||||||
specified task. If you do not specify a task, BitBake executes the
|
|
||||||
default task, which is "build". BitBake obeys inter-task dependencies
|
|
||||||
when doing so.
|
|
||||||
|
|
||||||
The following command runs the build task, which is the default task, on
|
|
||||||
the ``foo_1.0.bb`` recipe file::
|
|
||||||
|
|
||||||
$ bitbake -b foo_1.0.bb
|
|
||||||
|
|
||||||
The following command runs the clean task on the ``foo.bb`` recipe file::
|
|
||||||
|
|
||||||
$ bitbake -b foo.bb -c clean
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
The "-b" option explicitly does not handle recipe dependencies. Other
|
|
||||||
than for debugging purposes, it is instead recommended that you use
|
|
||||||
the syntax presented in the next section.
|
|
||||||
|
|
||||||
Executing Tasks Against a Set of Recipe Files
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
There are a number of additional complexities introduced when one wants
|
|
||||||
to manage multiple ``.bb`` files. Clearly there needs to be a way to
|
|
||||||
tell BitBake what files are available and, of those, which you want to
|
|
||||||
execute. There also needs to be a way for each recipe to express its
|
|
||||||
dependencies, both for build-time and runtime. There must be a way for
|
|
||||||
you to express recipe preferences when multiple recipes provide the same
|
|
||||||
functionality, or when there are multiple versions of a recipe.
|
|
||||||
|
|
||||||
The ``bitbake`` command, when not using "--buildfile" or "-b" only
|
|
||||||
accepts a "PROVIDES". You cannot provide anything else. By default, a
|
|
||||||
recipe file generally "PROVIDES" its "packagename" as shown in the
|
|
||||||
following example::
|
|
||||||
|
|
||||||
$ bitbake foo
|
|
||||||
|
|
||||||
This next example "PROVIDES" the
|
|
||||||
package name and also uses the "-c" option to tell BitBake to just
|
|
||||||
execute the ``do_clean`` task::
|
|
||||||
|
|
||||||
$ bitbake -c clean foo
|
|
||||||
|
|
||||||
Executing a List of Task and Recipe Combinations
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The BitBake command line supports specifying different tasks for
|
|
||||||
individual targets when you specify multiple targets. For example,
|
|
||||||
suppose you had two targets (or recipes) ``myfirstrecipe`` and
|
|
||||||
``mysecondrecipe`` and you needed BitBake to run ``taskA`` for the first
|
|
||||||
recipe and ``taskB`` for the second recipe::
|
|
||||||
|
|
||||||
$ bitbake myfirstrecipe:do_taskA mysecondrecipe:do_taskB
|
|
||||||
|
|
||||||
Generating Dependency Graphs
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
BitBake is able to generate dependency graphs using the ``dot`` syntax.
|
|
||||||
You can convert these graphs into images using the ``dot`` tool from
|
|
||||||
`Graphviz <http://www.graphviz.org>`__.
|
|
||||||
|
|
||||||
When you generate a dependency graph, BitBake writes two files to the
|
|
||||||
current working directory:
|
|
||||||
|
|
||||||
- ``task-depends.dot``: Shows dependencies between tasks. These
|
|
||||||
dependencies match BitBake's internal task execution list.
|
|
||||||
|
|
||||||
- ``pn-buildlist``: Shows a simple list of targets that are to be
|
|
||||||
built.
|
|
||||||
|
|
||||||
To stop depending on common depends, use the ``-I`` depend option and
|
|
||||||
BitBake omits them from the graph. Leaving this information out can
|
|
||||||
produce more readable graphs. This way, you can remove from the graph
|
|
||||||
:term:`DEPENDS` from inherited classes such as ``base.bbclass``.
|
|
||||||
|
|
||||||
Here are two examples that create dependency graphs. The second example
|
|
||||||
omits depends common in OpenEmbedded from the graph::
|
|
||||||
|
|
||||||
$ bitbake -g foo
|
|
||||||
|
|
||||||
$ bitbake -g -I virtual/kernel -I eglibc foo
|
|
||||||
|
|
||||||
Executing a Multiple Configuration Build
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
BitBake is able to build multiple images or packages using a single
|
|
||||||
command where the different targets require different configurations
|
|
||||||
(multiple configuration builds). Each target, in this scenario, is
|
|
||||||
referred to as a "multiconfig".
|
|
||||||
|
|
||||||
To accomplish a multiple configuration build, you must define each
|
|
||||||
target's configuration separately using a parallel configuration file in
|
|
||||||
the build directory. The location for these multiconfig configuration
|
|
||||||
files is specific. They must reside in the current build directory in a
|
|
||||||
sub-directory of ``conf`` named ``multiconfig``. Following is an example
|
|
||||||
for two separate targets:
|
|
||||||
|
|
||||||
.. image:: figures/bb_multiconfig_files.png
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
The reason for this required file hierarchy is because the :term:`BBPATH`
|
|
||||||
variable is not constructed until the layers are parsed. Consequently,
|
|
||||||
using the configuration file as a pre-configuration file is not possible
|
|
||||||
unless it is located in the current working directory.
|
|
||||||
|
|
||||||
Minimally, each configuration file must define the machine and the
|
|
||||||
temporary directory BitBake uses for the build. Suggested practice
|
|
||||||
dictates that you do not overlap the temporary directories used during
|
|
||||||
the builds.
|
|
||||||
|
|
||||||
Aside from separate configuration files for each target, you must also
|
|
||||||
enable BitBake to perform multiple configuration builds. Enabling is
|
|
||||||
accomplished by setting the
|
|
||||||
:term:`BBMULTICONFIG` variable in the
|
|
||||||
``local.conf`` configuration file. As an example, suppose you had
|
|
||||||
configuration files for ``target1`` and ``target2`` defined in the build
|
|
||||||
directory. The following statement in the ``local.conf`` file both
|
|
||||||
enables BitBake to perform multiple configuration builds and specifies
|
|
||||||
the two extra multiconfigs::
|
|
||||||
|
|
||||||
BBMULTICONFIG = "target1 target2"
|
|
||||||
|
|
||||||
Once the target configuration files are in place and BitBake has been
|
|
||||||
enabled to perform multiple configuration builds, use the following
|
|
||||||
command form to start the builds::
|
|
||||||
|
|
||||||
$ bitbake [mc:multiconfigname:]target [[[mc:multiconfigname:]target] ... ]
|
|
||||||
|
|
||||||
Here is an example for two extra multiconfigs: ``target1`` and ``target2``::
|
|
||||||
|
|
||||||
$ bitbake mc::target mc:target1:target mc:target2:target
|
|
||||||
|
|
||||||
.. _bb-enabling-multiple-configuration-build-dependencies:
|
|
||||||
|
|
||||||
Enabling Multiple Configuration Build Dependencies
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Sometimes dependencies can exist between targets (multiconfigs) in a
|
|
||||||
multiple configuration build. For example, suppose that in order to
|
|
||||||
build an image for a particular architecture, the root filesystem of
|
|
||||||
another build for a different architecture needs to exist. In other
|
|
||||||
words, the image for the first multiconfig depends on the root
|
|
||||||
filesystem of the second multiconfig. This dependency is essentially
|
|
||||||
that the task in the recipe that builds one multiconfig is dependent on
|
|
||||||
the completion of the task in the recipe that builds another
|
|
||||||
multiconfig.
|
|
||||||
|
|
||||||
To enable dependencies in a multiple configuration build, you must
|
|
||||||
declare the dependencies in the recipe using the following statement
|
|
||||||
form::
|
|
||||||
|
|
||||||
task_or_package[mcdepends] = "mc:from_multiconfig:to_multiconfig:recipe_name:task_on_which_to_depend"
|
|
||||||
|
|
||||||
To better show how to use this statement, consider an example with two
|
|
||||||
multiconfigs: ``target1`` and ``target2``::
|
|
||||||
|
|
||||||
image_task[mcdepends] = "mc:target1:target2:image2:rootfs_task"
|
|
||||||
|
|
||||||
In this example, the
|
|
||||||
``from_multiconfig`` is "target1" and the ``to_multiconfig`` is "target2". The
|
|
||||||
task on which the image whose recipe contains image_task depends on the
|
|
||||||
completion of the rootfs_task used to build out image2, which is
|
|
||||||
associated with the "target2" multiconfig.
|
|
||||||
|
|
||||||
Once you set up this dependency, you can build the "target1" multiconfig
|
|
||||||
using a BitBake command as follows::
|
|
||||||
|
|
||||||
$ bitbake mc:target1:image1
|
|
||||||
|
|
||||||
This command executes all the tasks needed to create ``image1`` for the "target1"
|
|
||||||
multiconfig. Because of the dependency, BitBake also executes through
|
|
||||||
the ``rootfs_task`` for the "target2" multiconfig build.
|
|
||||||
|
|
||||||
Having a recipe depend on the root filesystem of another build might not
|
|
||||||
seem that useful. Consider this change to the statement in the image1
|
|
||||||
recipe::
|
|
||||||
|
|
||||||
image_task[mcdepends] = "mc:target1:target2:image2:image_task"
|
|
||||||
|
|
||||||
In this case, BitBake must create ``image2`` for the "target2" build since
|
|
||||||
the "target1" build depends on it.
|
|
||||||
|
|
||||||
Because "target1" and "target2" are enabled for multiple configuration
|
|
||||||
builds and have separate configuration files, BitBake places the
|
|
||||||
artifacts for each build in the respective temporary build directories.
|
|
||||||
894
bitbake/doc/bitbake-user-manual/bitbake-user-manual-intro.xml
Normal file
894
bitbake/doc/bitbake-user-manual/bitbake-user-manual-intro.xml
Normal file
@@ -0,0 +1,894 @@
|
|||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<chapter id="bitbake-user-manual-intro">
|
||||||
|
<title>Overview</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Welcome to the BitBake User Manual.
|
||||||
|
This manual provides information on the BitBake tool.
|
||||||
|
The information attempts to be as independent as possible regarding
|
||||||
|
systems that use BitBake, such as OpenEmbedded and the
|
||||||
|
Yocto Project.
|
||||||
|
In some cases, scenarios or examples within the context of
|
||||||
|
a build system are used in the manual to help with understanding.
|
||||||
|
For these cases, the manual clearly states the context.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id="intro">
|
||||||
|
<title>Introduction</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Fundamentally, BitBake is a generic task execution
|
||||||
|
engine that allows shell and Python tasks to be run
|
||||||
|
efficiently and in parallel while working within
|
||||||
|
complex inter-task dependency constraints.
|
||||||
|
One of BitBake's main users, OpenEmbedded, takes this core
|
||||||
|
and builds embedded Linux software stacks using
|
||||||
|
a task-oriented approach.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Conceptually, BitBake is similar to GNU Make in
|
||||||
|
some regards but has significant differences:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
BitBake executes tasks according to provided
|
||||||
|
metadata that builds up the tasks.
|
||||||
|
Metadata is stored in recipe (<filename>.bb</filename>)
|
||||||
|
and related recipe "append" (<filename>.bbappend</filename>)
|
||||||
|
files, configuration (<filename>.conf</filename>) and
|
||||||
|
underlying include (<filename>.inc</filename>) files, and
|
||||||
|
in class (<filename>.bbclass</filename>) files.
|
||||||
|
The metadata provides
|
||||||
|
BitBake with instructions on what tasks to run and
|
||||||
|
the dependencies between those tasks.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
BitBake includes a fetcher library for obtaining source
|
||||||
|
code from various places such as local files, source control
|
||||||
|
systems, or websites.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
The instructions for each unit to be built (e.g. a piece
|
||||||
|
of software) are known as "recipe" files and
|
||||||
|
contain all the information about the unit
|
||||||
|
(dependencies, source file locations, checksums, description
|
||||||
|
and so on).
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
BitBake includes a client/server abstraction and can
|
||||||
|
be used from a command line or used as a service over
|
||||||
|
XML-RPC and has several different user interfaces.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="history-and-goals">
|
||||||
|
<title>History and Goals</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake was originally a part of the OpenEmbedded project.
|
||||||
|
It was inspired by the Portage package management system
|
||||||
|
used by the Gentoo Linux distribution.
|
||||||
|
On December 7, 2004, OpenEmbedded project team member
|
||||||
|
Chris Larson split the project into two distinct pieces:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>BitBake, a generic task executor</para></listitem>
|
||||||
|
<listitem><para>OpenEmbedded, a metadata set utilized by
|
||||||
|
BitBake</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
Today, BitBake is the primary basis of the
|
||||||
|
<ulink url="http://www.openembedded.org/">OpenEmbedded</ulink>
|
||||||
|
project, which is being used to build and maintain Linux
|
||||||
|
distributions such as the
|
||||||
|
<ulink url='http://www.angstrom-distribution.org/'>Angstrom Distribution</ulink>,
|
||||||
|
and which is also being used as the build tool for Linux projects
|
||||||
|
such as the
|
||||||
|
<ulink url='http://www.yoctoproject.org'>Yocto Project</ulink>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Prior to BitBake, no other build tool adequately met the needs of
|
||||||
|
an aspiring embedded Linux distribution.
|
||||||
|
All of the build systems used by traditional desktop Linux
|
||||||
|
distributions lacked important functionality, and none of the
|
||||||
|
ad hoc Buildroot-based systems, prevalent in the
|
||||||
|
embedded space, were scalable or maintainable.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Some important original goals for BitBake were:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
Handle cross-compilation.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Handle inter-package dependencies (build time on
|
||||||
|
target architecture, build time on native
|
||||||
|
architecture, and runtime).
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Support running any number of tasks within a given
|
||||||
|
package, including, but not limited to, fetching
|
||||||
|
upstream sources, unpacking them, patching them,
|
||||||
|
configuring them, and so forth.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Be Linux distribution agnostic for both build and
|
||||||
|
target systems.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Be architecture agnostic.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Support multiple build and target operating systems
|
||||||
|
(e.g. Cygwin, the BSDs, and so forth).
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Be self contained, rather than tightly
|
||||||
|
integrated into the build machine's root
|
||||||
|
filesystem.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Handle conditional metadata on the target architecture,
|
||||||
|
operating system, distribution, and machine.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Be easy to use the tools to supply local metadata and packages
|
||||||
|
against which to operate.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Be easy to use BitBake to collaborate between multiple
|
||||||
|
projects for their builds.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Provide an inheritance mechanism to share
|
||||||
|
common metadata between many packages.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
Over time it became apparent that some further requirements
|
||||||
|
were necessary:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
Handle variants of a base recipe (e.g. native, sdk,
|
||||||
|
and multilib).
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Split metadata into layers and allow layers
|
||||||
|
to enhance or override other layers.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Allow representation of a given set of input variables
|
||||||
|
to a task as a checksum.
|
||||||
|
Based on that checksum, allow acceleration of builds
|
||||||
|
with prebuilt components.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
BitBake satisfies all the original requirements and many more
|
||||||
|
with extensions being made to the basic functionality to
|
||||||
|
reflect the additional requirements.
|
||||||
|
Flexibility and power have always been the priorities.
|
||||||
|
BitBake is highly extensible and supports embedded Python code and
|
||||||
|
execution of any arbitrary tasks.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="Concepts">
|
||||||
|
<title>Concepts</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake is a program written in the Python language.
|
||||||
|
At the highest level, BitBake interprets metadata, decides
|
||||||
|
what tasks are required to run, and executes those tasks.
|
||||||
|
Similar to GNU Make, BitBake controls how software is
|
||||||
|
built.
|
||||||
|
GNU Make achieves its control through "makefiles", while
|
||||||
|
BitBake uses "recipes".
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake extends the capabilities of a simple
|
||||||
|
tool like GNU Make by allowing for the definition of much more
|
||||||
|
complex tasks, such as assembling entire embedded Linux
|
||||||
|
distributions.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The remainder of this section introduces several concepts
|
||||||
|
that should be understood in order to better leverage
|
||||||
|
the power of BitBake.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id='recipes'>
|
||||||
|
<title>Recipes</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake Recipes, which are denoted by the file extension
|
||||||
|
<filename>.bb</filename>, are the most basic metadata files.
|
||||||
|
These recipe files provide BitBake with the following:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>Descriptive information about the
|
||||||
|
package (author, homepage, license, and so on)</para></listitem>
|
||||||
|
<listitem><para>The version of the recipe</para></listitem>
|
||||||
|
<listitem><para>Existing dependencies (both build
|
||||||
|
and runtime dependencies)</para></listitem>
|
||||||
|
<listitem><para>Where the source code resides and
|
||||||
|
how to fetch it</para></listitem>
|
||||||
|
<listitem><para>Whether the source code requires
|
||||||
|
any patches, where to find them, and how to apply
|
||||||
|
them</para></listitem>
|
||||||
|
<listitem><para>How to configure and compile the
|
||||||
|
source code</para></listitem>
|
||||||
|
<listitem><para>Where on the target machine to install the
|
||||||
|
package or packages created</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Within the context of BitBake, or any project utilizing BitBake
|
||||||
|
as its build system, files with the <filename>.bb</filename>
|
||||||
|
extension are referred to as recipes.
|
||||||
|
<note>
|
||||||
|
The term "package" is also commonly used to describe recipes.
|
||||||
|
However, since the same word is used to describe packaged
|
||||||
|
output from a project, it is best to maintain a single
|
||||||
|
descriptive term - "recipes".
|
||||||
|
Put another way, a single "recipe" file is quite capable
|
||||||
|
of generating a number of related but separately installable
|
||||||
|
"packages".
|
||||||
|
In fact, that ability is fairly common.
|
||||||
|
</note>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='configuration-files'>
|
||||||
|
<title>Configuration Files</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Configuration files, which are denoted by the
|
||||||
|
<filename>.conf</filename> extension, define
|
||||||
|
various configuration variables that govern the project's build
|
||||||
|
process.
|
||||||
|
These files fall into several areas that define
|
||||||
|
machine configuration options, distribution configuration
|
||||||
|
options, compiler tuning options, general common
|
||||||
|
configuration options, and user configuration options.
|
||||||
|
The main configuration file is the sample
|
||||||
|
<filename>bitbake.conf</filename> file, which is
|
||||||
|
located within the BitBake source tree
|
||||||
|
<filename>conf</filename> directory.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='classes'>
|
||||||
|
<title>Classes</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Class files, which are denoted by the
|
||||||
|
<filename>.bbclass</filename> extension, contain
|
||||||
|
information that is useful to share between metadata files.
|
||||||
|
The BitBake source tree currently comes with one class metadata file
|
||||||
|
called <filename>base.bbclass</filename>.
|
||||||
|
You can find this file in the
|
||||||
|
<filename>classes</filename> directory.
|
||||||
|
The <filename>base.bbclass</filename> class files is special since it
|
||||||
|
is always included automatically for all recipes
|
||||||
|
and classes.
|
||||||
|
This class contains definitions for standard basic tasks such
|
||||||
|
as fetching, unpacking, configuring (empty by default),
|
||||||
|
compiling (runs any Makefile present), installing (empty by
|
||||||
|
default) and packaging (empty by default).
|
||||||
|
These tasks are often overridden or extended by other classes
|
||||||
|
added during the project development process.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='layers'>
|
||||||
|
<title>Layers</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Layers allow you to isolate different types of
|
||||||
|
customizations from each other.
|
||||||
|
While you might find it tempting to keep everything in one layer
|
||||||
|
when working on a single project, the more modular you organize
|
||||||
|
your metadata, the easier it is to cope with future changes.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To illustrate how you can use layers to keep things modular,
|
||||||
|
consider customizations you might make to support a specific target machine.
|
||||||
|
These types of customizations typically reside in a special layer,
|
||||||
|
rather than a general layer, called a Board Support Package (BSP)
|
||||||
|
Layer.
|
||||||
|
Furthermore, the machine customizations should be isolated from
|
||||||
|
recipes and metadata that support a new GUI environment, for
|
||||||
|
example.
|
||||||
|
This situation gives you a couple of layers: one for the machine
|
||||||
|
configurations and one for the GUI environment.
|
||||||
|
It is important to understand, however, that the BSP layer can still
|
||||||
|
make machine-specific additions to recipes within
|
||||||
|
the GUI environment layer without polluting the GUI layer itself
|
||||||
|
with those machine-specific changes.
|
||||||
|
You can accomplish this through a recipe that is a BitBake append
|
||||||
|
(<filename>.bbappend</filename>) file.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='append-bbappend-files'>
|
||||||
|
<title>Append Files</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Append files, which are files that have the
|
||||||
|
<filename>.bbappend</filename> file extension, extend or
|
||||||
|
override information in an existing recipe file.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake expects every append file to have a corresponding recipe file.
|
||||||
|
Furthermore, the append file and corresponding recipe file
|
||||||
|
must use the same root filename.
|
||||||
|
The filenames can differ only in the file type suffix used
|
||||||
|
(e.g. <filename>formfactor_0.0.bb</filename> and
|
||||||
|
<filename>formfactor_0.0.bbappend</filename>).
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Information in append files extends or
|
||||||
|
overrides the information in the underlying,
|
||||||
|
similarly-named recipe files.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When you name an append file, you can use the
|
||||||
|
"<filename>%</filename>" wildcard character to allow for matching
|
||||||
|
recipe names.
|
||||||
|
For example, suppose you have an append file named
|
||||||
|
as follows:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
busybox_1.21.%.bbappend
|
||||||
|
</literallayout>
|
||||||
|
That append file would match any <filename>busybox_1.21.</filename><replaceable>x</replaceable><filename>.bb</filename>
|
||||||
|
version of the recipe.
|
||||||
|
So, the append file would match the following recipe names:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
busybox_1.21.1.bb
|
||||||
|
busybox_1.21.2.bb
|
||||||
|
busybox_1.21.3.bb
|
||||||
|
</literallayout>
|
||||||
|
<note><title>Important</title>
|
||||||
|
The use of the "<filename>%</filename>" character
|
||||||
|
is limited in that it only works directly in front of the
|
||||||
|
<filename>.bbappend</filename> portion of the append file's
|
||||||
|
name.
|
||||||
|
You cannot use the wildcard character in any other
|
||||||
|
location of the name.
|
||||||
|
</note>
|
||||||
|
If the <filename>busybox</filename> recipe was updated to
|
||||||
|
<filename>busybox_1.3.0.bb</filename>, the append name would not
|
||||||
|
match.
|
||||||
|
However, if you named the append file
|
||||||
|
<filename>busybox_1.%.bbappend</filename>, then you would have a match.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In the most general case, you could name the append file something as
|
||||||
|
simple as <filename>busybox_%.bbappend</filename> to be entirely
|
||||||
|
version independent.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='obtaining-bitbake'>
|
||||||
|
<title>Obtaining BitBake</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
You can obtain BitBake several different ways:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><emphasis>Cloning BitBake:</emphasis>
|
||||||
|
Using Git to clone the BitBake source code repository
|
||||||
|
is the recommended method for obtaining BitBake.
|
||||||
|
Cloning the repository makes it easy to get bug fixes
|
||||||
|
and have access to stable branches and the master
|
||||||
|
branch.
|
||||||
|
Once you have cloned BitBake, you should use
|
||||||
|
the latest stable
|
||||||
|
branch for development since the master branch is for
|
||||||
|
BitBake development and might contain less stable changes.
|
||||||
|
</para>
|
||||||
|
<para>You usually need a version of BitBake
|
||||||
|
that matches the metadata you are using.
|
||||||
|
The metadata is generally backwards compatible but
|
||||||
|
not forward compatible.</para>
|
||||||
|
<para>Here is an example that clones the BitBake repository:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ git clone git://git.openembedded.org/bitbake
|
||||||
|
</literallayout>
|
||||||
|
This command clones the BitBake Git repository into a
|
||||||
|
directory called <filename>bitbake</filename>.
|
||||||
|
Alternatively, you can
|
||||||
|
designate a directory after the
|
||||||
|
<filename>git clone</filename> command
|
||||||
|
if you want to call the new directory something
|
||||||
|
other than <filename>bitbake</filename>.
|
||||||
|
Here is an example that names the directory
|
||||||
|
<filename>bbdev</filename>:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ git clone git://git.openembedded.org/bitbake bbdev
|
||||||
|
</literallayout></para></listitem>
|
||||||
|
<listitem><para><emphasis>Installation using your Distribution
|
||||||
|
Package Management System:</emphasis>
|
||||||
|
This method is not
|
||||||
|
recommended because the BitBake version that is
|
||||||
|
provided by your distribution, in most cases,
|
||||||
|
is several
|
||||||
|
releases behind a snapshot of the BitBake repository.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Taking a snapshot of BitBake:</emphasis>
|
||||||
|
Downloading a snapshot of BitBake from the
|
||||||
|
source code repository gives you access to a known
|
||||||
|
branch or release of BitBake.
|
||||||
|
<note>
|
||||||
|
Cloning the Git repository, as described earlier,
|
||||||
|
is the preferred method for getting BitBake.
|
||||||
|
Cloning the repository makes it easier to update as
|
||||||
|
patches are added to the stable branches.
|
||||||
|
</note></para>
|
||||||
|
<para>The following example downloads a snapshot of
|
||||||
|
BitBake version 1.17.0:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ wget http://git.openembedded.org/bitbake/snapshot/bitbake-1.17.0.tar.gz
|
||||||
|
$ tar zxpvf bitbake-1.17.0.tar.gz
|
||||||
|
</literallayout>
|
||||||
|
After extraction of the tarball using the tar utility,
|
||||||
|
you have a directory entitled
|
||||||
|
<filename>bitbake-1.17.0</filename>.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><emphasis>Using the BitBake that Comes With Your
|
||||||
|
Build Checkout:</emphasis>
|
||||||
|
A final possibility for getting a copy of BitBake is that it
|
||||||
|
already comes with your checkout of a larger Bitbake-based build
|
||||||
|
system, such as Poky.
|
||||||
|
Rather than manually checking out individual layers and
|
||||||
|
gluing them together yourself, you can check
|
||||||
|
out an entire build system.
|
||||||
|
The checkout will already include a version of BitBake that
|
||||||
|
has been thoroughly tested for compatibility with the other
|
||||||
|
components.
|
||||||
|
For information on how to check out a particular BitBake-based
|
||||||
|
build system, consult that build system's supporting documentation.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="bitbake-user-manual-command">
|
||||||
|
<title>The BitBake Command</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <filename>bitbake</filename> command is the primary interface
|
||||||
|
to the BitBake tool.
|
||||||
|
This section presents the BitBake command syntax and provides
|
||||||
|
several execution examples.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id='usage-and-syntax'>
|
||||||
|
<title>Usage and syntax</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Following is the usage and syntax for BitBake:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake -h
|
||||||
|
Usage: bitbake [options] [recipename/target recipe:do_task ...]
|
||||||
|
|
||||||
|
Executes the specified task (default is 'build') for a given set of target recipes (.bb files).
|
||||||
|
It is assumed there is a conf/bblayers.conf available in cwd or in BBPATH which
|
||||||
|
will provide the layer, BBFILES and other configuration information.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--version show program's version number and exit
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-b BUILDFILE, --buildfile=BUILDFILE
|
||||||
|
Execute tasks from a specific .bb recipe directly.
|
||||||
|
WARNING: Does not handle any dependencies from other
|
||||||
|
recipes.
|
||||||
|
-k, --continue Continue as much as possible after an error. While the
|
||||||
|
target that failed and anything depending on it cannot
|
||||||
|
be built, as much as possible will be built before
|
||||||
|
stopping.
|
||||||
|
-f, --force Force the specified targets/task to run (invalidating
|
||||||
|
any existing stamp file).
|
||||||
|
-c CMD, --cmd=CMD Specify the task to execute. The exact options
|
||||||
|
available depend on the metadata. Some examples might
|
||||||
|
be 'compile' or 'populate_sysroot' or 'listtasks' may
|
||||||
|
give a list of the tasks available.
|
||||||
|
-C INVALIDATE_STAMP, --clear-stamp=INVALIDATE_STAMP
|
||||||
|
Invalidate the stamp for the specified task such as
|
||||||
|
'compile' and then run the default task for the
|
||||||
|
specified target(s).
|
||||||
|
-r PREFILE, --read=PREFILE
|
||||||
|
Read the specified file before bitbake.conf.
|
||||||
|
-R POSTFILE, --postread=POSTFILE
|
||||||
|
Read the specified file after bitbake.conf.
|
||||||
|
-v, --verbose Enable tracing of shell tasks (with 'set -x'). Also
|
||||||
|
print bb.note(...) messages to stdout (in addition to
|
||||||
|
writing them to ${T}/log.do_<task>).
|
||||||
|
-D, --debug Increase the debug level. You can specify this more
|
||||||
|
than once. -D sets the debug level to 1, where only
|
||||||
|
bb.debug(1, ...) messages are printed to stdout; -DD
|
||||||
|
sets the debug level to 2, where both bb.debug(1, ...)
|
||||||
|
and bb.debug(2, ...) messages are printed; etc.
|
||||||
|
Without -D, no debug messages are printed. Note that
|
||||||
|
-D only affects output to stdout. All debug messages
|
||||||
|
are written to ${T}/log.do_taskname, regardless of the
|
||||||
|
debug level.
|
||||||
|
-q, --quiet Output less log message data to the terminal. You can
|
||||||
|
specify this more than once.
|
||||||
|
-n, --dry-run Don't execute, just go through the motions.
|
||||||
|
-S SIGNATURE_HANDLER, --dump-signatures=SIGNATURE_HANDLER
|
||||||
|
Dump out the signature construction information, with
|
||||||
|
no task execution. The SIGNATURE_HANDLER parameter is
|
||||||
|
passed to the handler. Two common values are none and
|
||||||
|
printdiff but the handler may define more/less. none
|
||||||
|
means only dump the signature, printdiff means compare
|
||||||
|
the dumped signature with the cached one.
|
||||||
|
-p, --parse-only Quit after parsing the BB recipes.
|
||||||
|
-s, --show-versions Show current and preferred versions of all recipes.
|
||||||
|
-e, --environment Show the global or per-recipe environment complete
|
||||||
|
with information about where variables were
|
||||||
|
set/changed.
|
||||||
|
-g, --graphviz Save dependency tree information for the specified
|
||||||
|
targets in the dot syntax.
|
||||||
|
-I EXTRA_ASSUME_PROVIDED, --ignore-deps=EXTRA_ASSUME_PROVIDED
|
||||||
|
Assume these dependencies don't exist and are already
|
||||||
|
provided (equivalent to ASSUME_PROVIDED). Useful to
|
||||||
|
make dependency graphs more appealing
|
||||||
|
-l DEBUG_DOMAINS, --log-domains=DEBUG_DOMAINS
|
||||||
|
Show debug logging for the specified logging domains
|
||||||
|
-P, --profile Profile the command and save reports.
|
||||||
|
-u UI, --ui=UI The user interface to use (knotty, ncurses or taskexp
|
||||||
|
- default knotty).
|
||||||
|
--token=XMLRPCTOKEN Specify the connection token to be used when
|
||||||
|
connecting to a remote server.
|
||||||
|
--revisions-changed Set the exit code depending on whether upstream
|
||||||
|
floating revisions have changed or not.
|
||||||
|
--server-only Run bitbake without a UI, only starting a server
|
||||||
|
(cooker) process.
|
||||||
|
-B BIND, --bind=BIND The name/address for the bitbake xmlrpc server to bind
|
||||||
|
to.
|
||||||
|
-T SERVER_TIMEOUT, --idle-timeout=SERVER_TIMEOUT
|
||||||
|
Set timeout to unload bitbake server due to
|
||||||
|
inactivity, set to -1 means no unload, default:
|
||||||
|
Environment variable BB_SERVER_TIMEOUT.
|
||||||
|
--no-setscene Do not run any setscene tasks. sstate will be ignored
|
||||||
|
and everything needed, built.
|
||||||
|
--setscene-only Only run setscene tasks, don't run any real tasks.
|
||||||
|
--remote-server=REMOTE_SERVER
|
||||||
|
Connect to the specified server.
|
||||||
|
-m, --kill-server Terminate any running bitbake server.
|
||||||
|
--observe-only Connect to a server as an observing-only client.
|
||||||
|
--status-only Check the status of the remote bitbake server.
|
||||||
|
-w WRITEEVENTLOG, --write-log=WRITEEVENTLOG
|
||||||
|
Writes the event log of the build to a bitbake event
|
||||||
|
json file. Use '' (empty string) to assign the name
|
||||||
|
automatically.
|
||||||
|
--runall=RUNALL Run the specified task for any recipe in the taskgraph
|
||||||
|
of the specified target (even if it wouldn't otherwise
|
||||||
|
have run).
|
||||||
|
--runonly=RUNONLY Run only the specified task within the taskgraph of
|
||||||
|
the specified targets (and any task dependencies those
|
||||||
|
tasks may have).
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bitbake-examples'>
|
||||||
|
<title>Examples</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This section presents some examples showing how to use BitBake.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id='example-executing-a-task-against-a-single-recipe'>
|
||||||
|
<title>Executing a Task Against a Single Recipe</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Executing tasks for a single recipe file is relatively simple.
|
||||||
|
You specify the file in question, and BitBake parses
|
||||||
|
it and executes the specified task.
|
||||||
|
If you do not specify a task, BitBake executes the default
|
||||||
|
task, which is "build”.
|
||||||
|
BitBake obeys inter-task dependencies when doing
|
||||||
|
so.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The following command runs the build task, which is
|
||||||
|
the default task, on the <filename>foo_1.0.bb</filename>
|
||||||
|
recipe file:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake -b foo_1.0.bb
|
||||||
|
</literallayout>
|
||||||
|
The following command runs the clean task on the
|
||||||
|
<filename>foo.bb</filename> recipe file:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake -b foo.bb -c clean
|
||||||
|
</literallayout>
|
||||||
|
<note>
|
||||||
|
The "-b" option explicitly does not handle recipe
|
||||||
|
dependencies.
|
||||||
|
Other than for debugging purposes, it is instead
|
||||||
|
recommended that you use the syntax presented in the
|
||||||
|
next section.
|
||||||
|
</note>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='executing-tasks-against-a-set-of-recipe-files'>
|
||||||
|
<title>Executing Tasks Against a Set of Recipe Files</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
There are a number of additional complexities introduced
|
||||||
|
when one wants to manage multiple <filename>.bb</filename>
|
||||||
|
files.
|
||||||
|
Clearly there needs to be a way to tell BitBake what
|
||||||
|
files are available and, of those, which you
|
||||||
|
want to execute.
|
||||||
|
There also needs to be a way for each recipe
|
||||||
|
to express its dependencies, both for build-time and
|
||||||
|
runtime.
|
||||||
|
There must be a way for you to express recipe preferences
|
||||||
|
when multiple recipes provide the same functionality, or when
|
||||||
|
there are multiple versions of a recipe.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <filename>bitbake</filename> command, when not using
|
||||||
|
"--buildfile" or "-b" only accepts a "PROVIDES".
|
||||||
|
You cannot provide anything else.
|
||||||
|
By default, a recipe file generally "PROVIDES" its
|
||||||
|
"packagename" as shown in the following example:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake foo
|
||||||
|
</literallayout>
|
||||||
|
This next example "PROVIDES" the package name and also uses
|
||||||
|
the "-c" option to tell BitBake to just execute the
|
||||||
|
<filename>do_clean</filename> task:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake -c clean foo
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='executing-a-list-of-task-and-recipe-combinations'>
|
||||||
|
<title>Executing a List of Task and Recipe Combinations</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The BitBake command line supports specifying different
|
||||||
|
tasks for individual targets when you specify multiple
|
||||||
|
targets.
|
||||||
|
For example, suppose you had two targets (or recipes)
|
||||||
|
<filename>myfirstrecipe</filename> and
|
||||||
|
<filename>mysecondrecipe</filename> and you needed
|
||||||
|
BitBake to run <filename>taskA</filename> for the first
|
||||||
|
recipe and <filename>taskB</filename> for the second
|
||||||
|
recipe:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake myfirstrecipe:do_taskA mysecondrecipe:do_taskB
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='generating-dependency-graphs'>
|
||||||
|
<title>Generating Dependency Graphs</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake is able to generate dependency graphs using
|
||||||
|
the <filename>dot</filename> syntax.
|
||||||
|
You can convert these graphs into images using the
|
||||||
|
<filename>dot</filename> tool from
|
||||||
|
<ulink url='http://www.graphviz.org'>Graphviz</ulink>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When you generate a dependency graph, BitBake writes three files
|
||||||
|
to the current working directory:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
<emphasis><filename>recipe-depends.dot</filename>:</emphasis>
|
||||||
|
Shows dependencies between recipes (i.e. a collapsed version of
|
||||||
|
<filename>task-depends.dot</filename>).
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
<emphasis><filename>task-depends.dot</filename>:</emphasis>
|
||||||
|
Shows dependencies between tasks.
|
||||||
|
These dependencies match BitBake's internal task execution list.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
<emphasis><filename>pn-buildlist</filename>:</emphasis>
|
||||||
|
Shows a simple list of targets that are to be built.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To stop depending on common depends, use the "-I" depend
|
||||||
|
option and BitBake omits them from the graph.
|
||||||
|
Leaving this information out can produce more readable graphs.
|
||||||
|
This way, you can remove from the graph
|
||||||
|
<filename>DEPENDS</filename> from inherited classes
|
||||||
|
such as <filename>base.bbclass</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Here are two examples that create dependency graphs.
|
||||||
|
The second example omits depends common in OpenEmbedded from
|
||||||
|
the graph:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake -g foo
|
||||||
|
|
||||||
|
$ bitbake -g -I virtual/kernel -I eglibc foo
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='executing-a-multiple-configuration-build'>
|
||||||
|
<title>Executing a Multiple Configuration Build</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
BitBake is able to build multiple images or packages
|
||||||
|
using a single command where the different targets
|
||||||
|
require different configurations (multiple configuration
|
||||||
|
builds).
|
||||||
|
Each target, in this scenario, is referred to as a
|
||||||
|
"multiconfig".
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To accomplish a multiple configuration build, you must
|
||||||
|
define each target's configuration separately using
|
||||||
|
a parallel configuration file in the build directory.
|
||||||
|
The location for these multiconfig configuration files
|
||||||
|
is specific.
|
||||||
|
They must reside in the current build directory in
|
||||||
|
a sub-directory of <filename>conf</filename> named
|
||||||
|
<filename>multiconfig</filename>.
|
||||||
|
Following is an example for two separate targets:
|
||||||
|
<imagedata fileref="figures/bb_multiconfig_files.png" align="center" width="4in" depth="3in" />
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The reason for this required file hierarchy
|
||||||
|
is because the <filename>BBPATH</filename> variable
|
||||||
|
is not constructed until the layers are parsed.
|
||||||
|
Consequently, using the configuration file as a
|
||||||
|
pre-configuration file is not possible unless it is
|
||||||
|
located in the current working directory.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Minimally, each configuration file must define the
|
||||||
|
machine and the temporary directory BitBake uses
|
||||||
|
for the build.
|
||||||
|
Suggested practice dictates that you do not
|
||||||
|
overlap the temporary directories used during the
|
||||||
|
builds.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Aside from separate configuration files for each
|
||||||
|
target, you must also enable BitBake to perform multiple
|
||||||
|
configuration builds.
|
||||||
|
Enabling is accomplished by setting the
|
||||||
|
<link linkend='var-bb-BBMULTICONFIG'><filename>BBMULTICONFIG</filename></link>
|
||||||
|
variable in the <filename>local.conf</filename>
|
||||||
|
configuration file.
|
||||||
|
As an example, suppose you had configuration files
|
||||||
|
for <filename>target1</filename> and
|
||||||
|
<filename>target2</filename> defined in the build
|
||||||
|
directory.
|
||||||
|
The following statement in the
|
||||||
|
<filename>local.conf</filename> file both enables
|
||||||
|
BitBake to perform multiple configuration builds and
|
||||||
|
specifies the two multiconfigs:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
BBMULTICONFIG = "target1 target2"
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Once the target configuration files are in place and
|
||||||
|
BitBake has been enabled to perform multiple configuration
|
||||||
|
builds, use the following command form to start the
|
||||||
|
builds:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake [multiconfig:<replaceable>multiconfigname</replaceable>:]<replaceable>target</replaceable> [[[multiconfig:<replaceable>multiconfigname</replaceable>:]<replaceable>target</replaceable>] ... ]
|
||||||
|
</literallayout>
|
||||||
|
Here is an example for two multiconfigs:
|
||||||
|
<filename>target1</filename> and
|
||||||
|
<filename>target2</filename>:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake multiconfig:target1:<replaceable>target</replaceable> multiconfig:target2:<replaceable>target</replaceable>
|
||||||
|
</literallayout>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bb-enabling-multiple-configuration-build-dependencies'>
|
||||||
|
<title>Enabling Multiple Configuration Build Dependencies</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Sometimes dependencies can exist between targets
|
||||||
|
(multiconfigs) in a multiple configuration build.
|
||||||
|
For example, suppose that in order to build an image
|
||||||
|
for a particular architecture, the root filesystem of
|
||||||
|
another build for a different architecture needs to
|
||||||
|
exist.
|
||||||
|
In other words, the image for the first multiconfig depends
|
||||||
|
on the root filesystem of the second multiconfig.
|
||||||
|
This dependency is essentially that the task in the recipe
|
||||||
|
that builds one multiconfig is dependent on the
|
||||||
|
completion of the task in the recipe that builds
|
||||||
|
another multiconfig.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To enable dependencies in a multiple configuration
|
||||||
|
build, you must declare the dependencies in the recipe
|
||||||
|
using the following statement form:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
<replaceable>task_or_package</replaceable>[mcdepends] = "multiconfig:<replaceable>from_multiconfig</replaceable>:<replaceable>to_multiconfig</replaceable>:<replaceable>recipe_name</replaceable>:<replaceable>task_on_which_to_depend</replaceable>"
|
||||||
|
</literallayout>
|
||||||
|
To better show how to use this statement, consider an
|
||||||
|
example with two multiconfigs: <filename>target1</filename>
|
||||||
|
and <filename>target2</filename>:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
<replaceable>image_task</replaceable>[mcdepends] = "multiconfig:target1:target2:<replaceable>image2</replaceable>:<replaceable>rootfs_task</replaceable>"
|
||||||
|
</literallayout>
|
||||||
|
In this example, the
|
||||||
|
<replaceable>from_multiconfig</replaceable> is "target1" and
|
||||||
|
the <replaceable>to_multiconfig</replaceable> is "target2".
|
||||||
|
The task on which the image whose recipe contains
|
||||||
|
<replaceable>image_task</replaceable> depends on the
|
||||||
|
completion of the <replaceable>rootfs_task</replaceable>
|
||||||
|
used to build out <replaceable>image2</replaceable>, which
|
||||||
|
is associated with the "target2" multiconfig.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Once you set up this dependency, you can build the
|
||||||
|
"target1" multiconfig using a BitBake command as follows:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
$ bitbake multiconfig:target1:<replaceable>image1</replaceable>
|
||||||
|
</literallayout>
|
||||||
|
This command executes all the tasks needed to create
|
||||||
|
<replaceable>image1</replaceable> for the "target1"
|
||||||
|
multiconfig.
|
||||||
|
Because of the dependency, BitBake also executes through
|
||||||
|
the <replaceable>rootfs_task</replaceable> for the "target2"
|
||||||
|
multiconfig build.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Having a recipe depend on the root filesystem of another
|
||||||
|
build might not seem that useful.
|
||||||
|
Consider this change to the statement in the
|
||||||
|
<replaceable>image1</replaceable> recipe:
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
<replaceable>image_task</replaceable>[mcdepends] = "multiconfig:target1:target2:<replaceable>image2</replaceable>:<replaceable>image_task</replaceable>"
|
||||||
|
</literallayout>
|
||||||
|
In this case, BitBake must create
|
||||||
|
<replaceable>image2</replaceable> for the "target2"
|
||||||
|
build since the "target1" build depends on it.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Because "target1" and "target2" are enabled for multiple
|
||||||
|
configuration builds and have separate configuration
|
||||||
|
files, BitBake places the artifacts for each build in the
|
||||||
|
respective temporary build directories.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</chapter>
|
||||||
File diff suppressed because it is too large
Load Diff
2781
bitbake/doc/bitbake-user-manual/bitbake-user-manual-metadata.xml
Normal file
2781
bitbake/doc/bitbake-user-manual/bitbake-user-manual-metadata.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,91 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: CC-BY-2.5
|
|
||||||
|
|
||||||
================
|
|
||||||
Variable Context
|
|
||||||
================
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
Variables might only have an impact or can be used in certain contexts. Some
|
|
||||||
should only be used in global files like ``.conf``, while others are intended only
|
|
||||||
for local files like ``.bb``. This chapter aims to describe some important variable
|
|
||||||
contexts.
|
|
||||||
|
|
||||||
.. _ref-varcontext-configuration:
|
|
||||||
|
|
||||||
BitBake's own configuration
|
|
||||||
===========================
|
|
||||||
|
|
||||||
Variables starting with ``BB_`` usually configure the behaviour of BitBake itself.
|
|
||||||
For example, one could configure:
|
|
||||||
|
|
||||||
- System resources, like disk space to be used (:term:`BB_DISKMON_DIRS`),
|
|
||||||
or the number of tasks to be run in parallel by BitBake (:term:`BB_NUMBER_THREADS`).
|
|
||||||
|
|
||||||
- How the fetchers shall behave, e.g., :term:`BB_FETCH_PREMIRRORONLY` is used
|
|
||||||
by BitBake to determine if BitBake's fetcher shall search only
|
|
||||||
:term:`PREMIRRORS` for files.
|
|
||||||
|
|
||||||
Those variables are usually configured globally.
|
|
||||||
|
|
||||||
BitBake configuration
|
|
||||||
=====================
|
|
||||||
|
|
||||||
There are variables:
|
|
||||||
|
|
||||||
- Like :term:`B` or :term:`T`, that are used to specify directories used by
|
|
||||||
BitBake during the build of a particular recipe. Those variables are
|
|
||||||
specified in ``bitbake.conf``. Some, like :term:`B`, are quite often
|
|
||||||
overwritten in recipes.
|
|
||||||
|
|
||||||
- Starting with ``FAKEROOT``, to configure how the ``fakeroot`` command is
|
|
||||||
handled. Those are usually set by ``bitbake.conf`` and might get adapted in a
|
|
||||||
``bbclass``.
|
|
||||||
|
|
||||||
- Detailing where BitBake will store and fetch information from, for
|
|
||||||
data reuse between build runs like :term:`CACHE`, :term:`DL_DIR` or
|
|
||||||
:term:`PERSISTENT_DIR`. Those are usually global.
|
|
||||||
|
|
||||||
|
|
||||||
Layers and files
|
|
||||||
================
|
|
||||||
|
|
||||||
Variables starting with ``LAYER`` configure how BitBake handles layers.
|
|
||||||
Additionally, variables starting with ``BB`` configure how layers and files are
|
|
||||||
handled. For example:
|
|
||||||
|
|
||||||
- :term:`LAYERDEPENDS` is used to configure on which layers a given layer
|
|
||||||
depends.
|
|
||||||
|
|
||||||
- The configured layers are contained in :term:`BBLAYERS` and files in
|
|
||||||
:term:`BBFILES`.
|
|
||||||
|
|
||||||
Those variables are often used in the files ``layer.conf`` and ``bblayers.conf``.
|
|
||||||
|
|
||||||
Recipes and packages
|
|
||||||
====================
|
|
||||||
|
|
||||||
Variables handling recipes and packages can be split into:
|
|
||||||
|
|
||||||
- :term:`PN`, :term:`PV` or :term:`PF` for example, contain information about
|
|
||||||
the name or revision of a recipe or package. Usually, the default set in
|
|
||||||
``bitbake.conf`` is used, but those are from time to time overwritten in
|
|
||||||
recipes.
|
|
||||||
|
|
||||||
- :term:`SUMMARY`, :term:`DESCRIPTION`, :term:`LICENSE` or :term:`HOMEPAGE`
|
|
||||||
contain the expected information and should be set specifically for every
|
|
||||||
recipe.
|
|
||||||
|
|
||||||
- In recipes, variables are also used to control build and runtime
|
|
||||||
dependencies between recipes/packages with other recipes/packages. The
|
|
||||||
most common should be: :term:`PROVIDES`, :term:`RPROVIDES`, :term:`DEPENDS`,
|
|
||||||
and :term:`RDEPENDS`.
|
|
||||||
|
|
||||||
- There are further variables starting with ``SRC`` that specify the sources in
|
|
||||||
a recipe like :term:`SRC_URI` or :term:`SRCDATE`. Those are also usually set
|
|
||||||
in recipes.
|
|
||||||
|
|
||||||
- Which version or provider of a recipe should be given preference when
|
|
||||||
multiple recipes would provide the same item, is controlled by variables
|
|
||||||
starting with ``PREFERRED_``. Those are normally set in the configuration
|
|
||||||
files of a ``MACHINE`` or ``DISTRO``.
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
984
bitbake/doc/bitbake-user-manual/bitbake-user-manual-style.css
Normal file
984
bitbake/doc/bitbake-user-manual/bitbake-user-manual-style.css
Normal file
@@ -0,0 +1,984 @@
|
|||||||
|
/*
|
||||||
|
Generic XHTML / DocBook XHTML CSS Stylesheet.
|
||||||
|
|
||||||
|
Browser wrangling and typographic design by
|
||||||
|
Oyvind Kolas / pippin@gimp.org
|
||||||
|
|
||||||
|
Customised for Poky by
|
||||||
|
Matthew Allum / mallum@o-hand.com
|
||||||
|
|
||||||
|
Thanks to:
|
||||||
|
Liam R. E. Quin
|
||||||
|
William Skaggs
|
||||||
|
Jakub Steiner
|
||||||
|
|
||||||
|
Structure
|
||||||
|
---------
|
||||||
|
|
||||||
|
The stylesheet is divided into the following sections:
|
||||||
|
|
||||||
|
Positioning
|
||||||
|
Margins, paddings, width, font-size, clearing.
|
||||||
|
Decorations
|
||||||
|
Borders, style
|
||||||
|
Colors
|
||||||
|
Colors
|
||||||
|
Graphics
|
||||||
|
Graphical backgrounds
|
||||||
|
Nasty IE tweaks
|
||||||
|
Workarounds needed to make it work in internet explorer,
|
||||||
|
currently makes the stylesheet non validating, but up until
|
||||||
|
this point it is validating.
|
||||||
|
Mozilla extensions
|
||||||
|
Transparency for footer
|
||||||
|
Rounded corners on boxes
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*************** /
|
||||||
|
/ Positioning /
|
||||||
|
/ ***************/
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Verdana, Sans, sans-serif;
|
||||||
|
|
||||||
|
min-width: 640px;
|
||||||
|
width: 80%;
|
||||||
|
margin: 0em auto;
|
||||||
|
padding: 2em 5em 5em 5em;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,h2,h3,h4,h5,h6,h7 {
|
||||||
|
font-family: Arial, Sans;
|
||||||
|
color: #00557D;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
text-align: left;
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
margin: 2em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2.subtitle {
|
||||||
|
margin: 0.10em 0em 3.0em 0em;
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
font-size: 1.8em;
|
||||||
|
padding-left: 20%;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 2em 0em 0.66em 0em;
|
||||||
|
padding: 0.5em 0em 0em 0em;
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.subtitle {
|
||||||
|
margin: 0em 0em 1em 0em;
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
font-size: 142.14%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 1em 0em 0.5em 0em;
|
||||||
|
padding: 1em 0em 0em 0em;
|
||||||
|
font-size: 140%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 1em 0em 0.5em 0em;
|
||||||
|
padding: 1em 0em 0em 0em;
|
||||||
|
font-size: 120%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
margin: 1em 0em 0.5em 0em;
|
||||||
|
padding: 1em 0em 0em 0em;
|
||||||
|
font-size: 110%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
margin: 1em 0em 0em 0em;
|
||||||
|
padding: 1em 0em 0em 0em;
|
||||||
|
font-size: 110%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.authorgroup {
|
||||||
|
background-color: transparent;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
padding-top: 256px;
|
||||||
|
background-image: url("figures/bitbake-title.png");
|
||||||
|
background-position: left top;
|
||||||
|
margin-top: -256px;
|
||||||
|
padding-right: 50px;
|
||||||
|
margin-left: 0px;
|
||||||
|
text-align: right;
|
||||||
|
width: 740px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.author {
|
||||||
|
margin: 0em 0me 0em 0em;
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 100%;
|
||||||
|
color: #333;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author tt.email {
|
||||||
|
font-size: 66%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titlepage hr {
|
||||||
|
width: 0em;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.revhistory {
|
||||||
|
padding-top: 2em;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc,
|
||||||
|
.list-of-tables,
|
||||||
|
.list-of-examples,
|
||||||
|
.list-of-figures {
|
||||||
|
padding: 1.33em 0em 2.5em 0em;
|
||||||
|
color: #00557D;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc p,
|
||||||
|
.list-of-tables p,
|
||||||
|
.list-of-figures p,
|
||||||
|
.list-of-examples p {
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
padding: 0em 0em 0.3em;
|
||||||
|
margin: 1.5em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc p b,
|
||||||
|
.list-of-tables p b,
|
||||||
|
.list-of-figures p b,
|
||||||
|
.list-of-examples p b{
|
||||||
|
font-size: 100.0%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc dl,
|
||||||
|
.list-of-tables dl,
|
||||||
|
.list-of-figures dl,
|
||||||
|
.list-of-examples dl {
|
||||||
|
margin: 0em 0em 0.5em 0em;
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc dt {
|
||||||
|
margin: 0em 0em 0em 0em;
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc dd {
|
||||||
|
margin: 0em 0em 0em 2.6em;
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.glossary dl,
|
||||||
|
div.variablelist dl {
|
||||||
|
}
|
||||||
|
|
||||||
|
.glossary dl dt,
|
||||||
|
.variablelist dl dt,
|
||||||
|
.variablelist dl dt span.term {
|
||||||
|
font-weight: normal;
|
||||||
|
width: 20em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.variablelist dl dt {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glossary dl dd,
|
||||||
|
.variablelist dl dd {
|
||||||
|
margin-top: -1em;
|
||||||
|
margin-left: 25.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glossary dd p,
|
||||||
|
.variablelist dd p {
|
||||||
|
margin-top: 0em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.calloutlist table td {
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
margin: 0em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.calloutlist table td p {
|
||||||
|
margin-top: 0em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div p.copyright {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.legalnotice p.legalnotice-title {
|
||||||
|
margin-bottom: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-top: 0em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dl {
|
||||||
|
padding-top: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: solid 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.mediaobject,
|
||||||
|
.mediaobjectco {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0em 0em 0em 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li {
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li p {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width :100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
padding: 0.25em;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: normal;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0.25em;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
p a[id] {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
display: inline;
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
/*font-weight: bold;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This style defines how the permalink character
|
||||||
|
appears by itself and when hovered over with
|
||||||
|
the mouse. */
|
||||||
|
|
||||||
|
[alt='Permalink'] { color: #eee; }
|
||||||
|
[alt='Permalink']:hover { color: black; }
|
||||||
|
|
||||||
|
|
||||||
|
div.informalfigure,
|
||||||
|
div.informalexample,
|
||||||
|
div.informaltable,
|
||||||
|
div.figure,
|
||||||
|
div.table,
|
||||||
|
div.example {
|
||||||
|
margin: 1em 0em;
|
||||||
|
padding: 1em;
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.informalfigure p.title b,
|
||||||
|
div.informalexample p.title b,
|
||||||
|
div.informaltable p.title b,
|
||||||
|
div.figure p.title b,
|
||||||
|
div.example p.title b,
|
||||||
|
div.table p.title b{
|
||||||
|
padding-top: 0em;
|
||||||
|
margin-top: 0em;
|
||||||
|
font-size: 100%;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mediaobject .caption,
|
||||||
|
.mediaobject .caption p {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 80%;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.epigraph {
|
||||||
|
padding-left: 55%;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.epigraph p {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.epigraph .quote {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.epigraph .attribution {
|
||||||
|
font-style: normal;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.application {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.programlisting {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 80%;
|
||||||
|
white-space: pre;
|
||||||
|
margin: 1.33em 0em;
|
||||||
|
padding: 1.33em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip,
|
||||||
|
.warning,
|
||||||
|
.caution,
|
||||||
|
.note {
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* force full width of table within div */
|
||||||
|
.tip table,
|
||||||
|
.warning table,
|
||||||
|
.caution table,
|
||||||
|
.note table {
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tip table th,
|
||||||
|
.warning table th,
|
||||||
|
.caution table th,
|
||||||
|
.note table th {
|
||||||
|
padding: 0.8em 0.0em 0.0em 0.0em;
|
||||||
|
margin : 0em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip p,
|
||||||
|
.warning p,
|
||||||
|
.caution p,
|
||||||
|
.note p {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
padding-right: 1em;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.acronym {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.keycap,
|
||||||
|
.keycap {
|
||||||
|
padding: 0.09em 0.3em;
|
||||||
|
margin: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.itemizedlist li {
|
||||||
|
clear: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filename {
|
||||||
|
font-size: medium;
|
||||||
|
font-family: Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.navheader, div.heading{
|
||||||
|
position: absolute;
|
||||||
|
left: 0em;
|
||||||
|
top: 0em;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #cdf;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navfooter, div.footing{
|
||||||
|
position: fixed;
|
||||||
|
left: 0em;
|
||||||
|
bottom: 0em;
|
||||||
|
background-color: #eee;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.navheader td,
|
||||||
|
div.navfooter td {
|
||||||
|
font-size: 66%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navheader table th {
|
||||||
|
/*font-family: Georgia, Times, serif;*/
|
||||||
|
/*font-size: x-large;*/
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navheader table {
|
||||||
|
border-left: 0em;
|
||||||
|
border-right: 0em;
|
||||||
|
border-top: 0em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navfooter table {
|
||||||
|
border-left: 0em;
|
||||||
|
border-right: 0em;
|
||||||
|
border-bottom: 0em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navheader table td a,
|
||||||
|
div.navfooter table td a {
|
||||||
|
color: #777;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* normal text in the footer */
|
||||||
|
div.navfooter table td {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navheader table td a:visited,
|
||||||
|
div.navfooter table td a:visited {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* links in header and footer */
|
||||||
|
div.navheader table td a:hover,
|
||||||
|
div.navfooter table td a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #33a;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navheader hr,
|
||||||
|
div.navfooter hr {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.qandaset tr.question td p {
|
||||||
|
margin: 0em 0em 1em 0em;
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qandaset tr.answer td p {
|
||||||
|
margin: 0em 0em 1em 0em;
|
||||||
|
padding: 0em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
.answer td {
|
||||||
|
padding-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emphasis {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************* /
|
||||||
|
/ decorations /
|
||||||
|
/ *************/
|
||||||
|
|
||||||
|
.titlepage {
|
||||||
|
}
|
||||||
|
|
||||||
|
.part .title {
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
h1 {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
border-top: solid 0.2em;
|
||||||
|
border-bottom: solid 0.06em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
border-top: 0em;
|
||||||
|
border-bottom: solid 0.06em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
border: 0em;
|
||||||
|
border-bottom: solid 0.06em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
border: 0em;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
.programlisting {
|
||||||
|
border: solid 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.figure,
|
||||||
|
div.table,
|
||||||
|
div.informalfigure,
|
||||||
|
div.informaltable,
|
||||||
|
div.informalexample,
|
||||||
|
div.example {
|
||||||
|
border: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.tip,
|
||||||
|
.warning,
|
||||||
|
.caution,
|
||||||
|
.note {
|
||||||
|
border: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip table th,
|
||||||
|
.warning table th,
|
||||||
|
.caution table th,
|
||||||
|
.note table th {
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question td {
|
||||||
|
border-top: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.answer {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
b.keycap,
|
||||||
|
.keycap {
|
||||||
|
border: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.navheader, div.heading{
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.navfooter, div.footing{
|
||||||
|
border-top: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********* /
|
||||||
|
/ colors /
|
||||||
|
/ *********/
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: #333;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
background-color: #dedede;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
h7,
|
||||||
|
h8 {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tip, .warning, .caution, .note {
|
||||||
|
border-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tip table th,
|
||||||
|
.warning table th,
|
||||||
|
.caution table th,
|
||||||
|
.note table th {
|
||||||
|
border-bottom-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
background-color: #f0f0f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caution {
|
||||||
|
background-color: #f0f0f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
background-color: #f0f0f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note {
|
||||||
|
background-color: #f0f0f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glossary dl dt,
|
||||||
|
.variablelist dl dt,
|
||||||
|
.variablelist dl dt span.term {
|
||||||
|
color: #044;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.figure,
|
||||||
|
div.table,
|
||||||
|
div.example,
|
||||||
|
div.informalfigure,
|
||||||
|
div.informaltable,
|
||||||
|
div.informalexample {
|
||||||
|
border-color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.programlisting {
|
||||||
|
color: black;
|
||||||
|
background-color: #fff;
|
||||||
|
border-color: #aaa;
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guimenu,
|
||||||
|
.guilabel,
|
||||||
|
.guimenuitem {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
b.keycap,
|
||||||
|
.keycap {
|
||||||
|
background-color: #eee;
|
||||||
|
border-color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.navheader {
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.navfooter {
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********** /
|
||||||
|
/ graphics /
|
||||||
|
/ ***********/
|
||||||
|
|
||||||
|
/*
|
||||||
|
body {
|
||||||
|
background-image: url("images/body_bg.jpg");
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navheader,
|
||||||
|
.note,
|
||||||
|
.tip {
|
||||||
|
background-image: url("images/note_bg.jpg");
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning,
|
||||||
|
.caution {
|
||||||
|
background-image: url("images/warning_bg.jpg");
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.figure,
|
||||||
|
.informalfigure,
|
||||||
|
.example,
|
||||||
|
.informalexample,
|
||||||
|
.table,
|
||||||
|
.informaltable {
|
||||||
|
background-image: url("images/figure_bg.jpg");
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
h7{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Example of how to stick an image as part of the title.
|
||||||
|
|
||||||
|
div.article .titlepage .title
|
||||||
|
{
|
||||||
|
background-image: url("figures/white-on-black.png");
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
div.preface .titlepage .title,
|
||||||
|
div.colophon .title,
|
||||||
|
div.chapter .titlepage .title,
|
||||||
|
div.article .titlepage .title
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
div.section div.section .titlepage .title,
|
||||||
|
div.sect2 .titlepage .title {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
background-color: transparent;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
height: 256px;
|
||||||
|
text-indent: -9000px;
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2.subtitle {
|
||||||
|
background-color: transparent;
|
||||||
|
text-indent: -9000px;
|
||||||
|
overflow:hidden;
|
||||||
|
width: 0px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************** /
|
||||||
|
/ pippin.gimp.org specific alterations /
|
||||||
|
/ ***************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
div.heading, div.navheader {
|
||||||
|
color: #777;
|
||||||
|
font-size: 80%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
text-align: left;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
background: url('/gfx/heading_bg.png') transparent;
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
background-attachment: fixed;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.heading a {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footing, div.navfooter {
|
||||||
|
border: none;
|
||||||
|
color: #ddd;
|
||||||
|
font-size: 80%;
|
||||||
|
text-align:right;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 10px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
|
||||||
|
background: url('/gfx/footing_bg.png') transparent;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/****************** /
|
||||||
|
/ nasty ie tweaks /
|
||||||
|
/ ******************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
div.heading, div.navheader {
|
||||||
|
width:expression(document.body.clientWidth + "px");
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footing, div.navfooter {
|
||||||
|
width:expression(document.body.clientWidth + "px");
|
||||||
|
margin-left:expression("-5em");
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
padding:expression("4em 5em 0em 5em");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**************************************** /
|
||||||
|
/ mozilla vendor specific css extensions /
|
||||||
|
/ ****************************************/
|
||||||
|
/*
|
||||||
|
div.navfooter, div.footing{
|
||||||
|
-moz-opacity: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.figure,
|
||||||
|
div.table,
|
||||||
|
div.informalfigure,
|
||||||
|
div.informaltable,
|
||||||
|
div.informalexample,
|
||||||
|
div.example,
|
||||||
|
.tip,
|
||||||
|
.warning,
|
||||||
|
.caution,
|
||||||
|
.note {
|
||||||
|
-moz-border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.keycap,
|
||||||
|
.keycap {
|
||||||
|
-moz-border-radius: 0.3em;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
table tr td table tr td {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hr {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo {
|
||||||
|
float: right;
|
||||||
|
margin-left: 1.5em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
margin-top: 0em;
|
||||||
|
max-width: 17em;
|
||||||
|
border: 1px solid gray;
|
||||||
|
padding: 3px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
.seperator {
|
||||||
|
padding-top: 2em;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
#validators {
|
||||||
|
margin-top: 5em;
|
||||||
|
text-align: right;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
@media print {
|
||||||
|
body {
|
||||||
|
font-size: 8pt;
|
||||||
|
}
|
||||||
|
.noprint {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tip,
|
||||||
|
.note {
|
||||||
|
background: #f0f0f2;
|
||||||
|
color: #333;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip h3,
|
||||||
|
.note h3 {
|
||||||
|
padding: 0em;
|
||||||
|
margin: 0em;
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip a,
|
||||||
|
.note a {
|
||||||
|
color: #333;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footnote {
|
||||||
|
font-size: small;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Changes the announcement text */
|
||||||
|
.tip h3,
|
||||||
|
.warning h3,
|
||||||
|
.caution h3,
|
||||||
|
.note h3 {
|
||||||
|
font-size:large;
|
||||||
|
color: #00557D;
|
||||||
|
}
|
||||||
88
bitbake/doc/bitbake-user-manual/bitbake-user-manual.xml
Normal file
88
bitbake/doc/bitbake-user-manual/bitbake-user-manual.xml
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<book id='bitbake-user-manual' lang='en'
|
||||||
|
xmlns:xi="http://www.w3.org/2003/XInclude"
|
||||||
|
xmlns="http://docbook.org/ns/docbook"
|
||||||
|
>
|
||||||
|
<bookinfo>
|
||||||
|
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref='figures/bitbake-title.png'
|
||||||
|
format='SVG'
|
||||||
|
align='left' scalefit='1' width='100%'/>
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
|
||||||
|
<title>
|
||||||
|
BitBake User Manual
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<authorgroup>
|
||||||
|
<author>
|
||||||
|
<firstname>Richard Purdie, Chris Larson, and </firstname> <surname>Phil Blundell</surname>
|
||||||
|
<affiliation>
|
||||||
|
<orgname>BitBake Community</orgname>
|
||||||
|
</affiliation>
|
||||||
|
<email>bitbake-devel@lists.openembedded.org</email>
|
||||||
|
</author>
|
||||||
|
</authorgroup>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
# Add in some revision history if we want it here.
|
||||||
|
<revhistory>
|
||||||
|
<revision>
|
||||||
|
<revnumber>x.x</revnumber>
|
||||||
|
<date>dd month year</date>
|
||||||
|
<revremark>Some relevent comment</revremark>
|
||||||
|
</revision>
|
||||||
|
<revision>
|
||||||
|
<revnumber>x.x</revnumber>
|
||||||
|
<date>dd month year</date>
|
||||||
|
<revremark>Some relevent comment</revremark>
|
||||||
|
</revision>
|
||||||
|
<revision>
|
||||||
|
<revnumber>x.x</revnumber>
|
||||||
|
<date>dd month year</date>
|
||||||
|
<revremark>Some relevent comment</revremark>
|
||||||
|
</revision>
|
||||||
|
<revision>
|
||||||
|
<revnumber>x.x</revnumber>
|
||||||
|
<date>dd month year</date>
|
||||||
|
<revremark>Some relevent comment</revremark>
|
||||||
|
</revision>
|
||||||
|
</revhistory>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
<year>2004-2018</year>
|
||||||
|
<holder>Richard Purdie</holder>
|
||||||
|
<holder>Chris Larson</holder>
|
||||||
|
<holder>and Phil Blundell</holder>
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<legalnotice>
|
||||||
|
<para>
|
||||||
|
This work is licensed under the Creative Commons Attribution License.
|
||||||
|
To view a copy of this license, visit
|
||||||
|
<ulink url="http://creativecommons.org/licenses/by/2.5/">http://creativecommons.org/licenses/by/2.5/</ulink>
|
||||||
|
or send a letter to Creative Commons, 444 Castro Street,
|
||||||
|
Suite 900, Mountain View, California 94041, USA.
|
||||||
|
</para>
|
||||||
|
</legalnotice>
|
||||||
|
</bookinfo>
|
||||||
|
|
||||||
|
<xi:include href="bitbake-user-manual-intro.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="bitbake-user-manual-execution.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="bitbake-user-manual-metadata.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="bitbake-user-manual-fetching.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="bitbake-user-manual-ref-variables.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="bitbake-user-manual-hello.xml"/>
|
||||||
|
|
||||||
|
</book>
|
||||||
281
bitbake/doc/bitbake-user-manual/html.css
Normal file
281
bitbake/doc/bitbake-user-manual/html.css
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
/* Feuille de style DocBook du projet Traduc.org */
|
||||||
|
/* DocBook CSS stylesheet of the Traduc.org project */
|
||||||
|
|
||||||
|
/* (c) Jean-Philippe Gu<47>rard - 14 ao<61>t 2004 */
|
||||||
|
/* (c) Jean-Philippe Gu<47>rard - 14 August 2004 */
|
||||||
|
|
||||||
|
/* Cette feuille de style est libre, vous pouvez la */
|
||||||
|
/* redistribuer et la modifier selon les termes de la Licence */
|
||||||
|
/* Art Libre. Vous trouverez un exemplaire de cette Licence sur */
|
||||||
|
/* http://tigreraye.org/Petit-guide-du-traducteur.html#licence-art-libre */
|
||||||
|
|
||||||
|
/* This work of art is free, you can redistribute it and/or */
|
||||||
|
/* modify it according to terms of the Free Art license. You */
|
||||||
|
/* will find a specimen of this license on the Copyleft */
|
||||||
|
/* Attitude web site: http://artlibre.org as well as on other */
|
||||||
|
/* sites. */
|
||||||
|
/* Please note that the French version of this licence as shown */
|
||||||
|
/* on http://tigreraye.org/Petit-guide-du-traducteur.html#licence-art-libre */
|
||||||
|
/* is only official licence of this document. The English */
|
||||||
|
/* is only provided to help you understand this licence. */
|
||||||
|
|
||||||
|
/* La derni<6E>re version de cette feuille de style est toujours */
|
||||||
|
/* disponible sur<75>: http://tigreraye.org/style.css */
|
||||||
|
/* Elle est <20>galement disponible sur<75>: */
|
||||||
|
/* http://www.traduc.org/docs/HOWTO/lecture/style.css */
|
||||||
|
|
||||||
|
/* The latest version of this stylesheet is available from: */
|
||||||
|
/* http://tigreraye.org/style.css */
|
||||||
|
/* It is also available on: */
|
||||||
|
/* http://www.traduc.org/docs/HOWTO/lecture/style.css */
|
||||||
|
|
||||||
|
/* N'h<>sitez pas <20> envoyer vos commentaires et corrections <20> */
|
||||||
|
/* Jean-Philippe Gu<47>rard <jean-philippe.guerard@tigreraye.org> */
|
||||||
|
|
||||||
|
/* Please send feedback and bug reports to */
|
||||||
|
/* Jean-Philippe Gu<47>rard <jean-philippe.guerard@tigreraye.org> */
|
||||||
|
|
||||||
|
/* $Id: style.css,v 1.14 2004/09/10 20:12:09 fevrier Exp fevrier $ */
|
||||||
|
|
||||||
|
/* Pr<50>sentation g<>n<EFBFBD>rale du document */
|
||||||
|
/* Overall document presentation */
|
||||||
|
|
||||||
|
body {
|
||||||
|
/*
|
||||||
|
font-family: Apolline, "URW Palladio L", Garamond, jGaramond,
|
||||||
|
"Bitstream Cyberbit", "Palatino Linotype", serif;
|
||||||
|
*/
|
||||||
|
margin: 7%;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Taille du texte */
|
||||||
|
/* Text size */
|
||||||
|
|
||||||
|
* { font-size: 100%; }
|
||||||
|
|
||||||
|
/* Gestion des textes mis en relief imbriqu<71>s */
|
||||||
|
/* Embedded emphasis */
|
||||||
|
|
||||||
|
em { font-style: italic; }
|
||||||
|
em em { font-style: normal; }
|
||||||
|
em em em { font-style: italic; }
|
||||||
|
|
||||||
|
/* Titres */
|
||||||
|
/* Titles */
|
||||||
|
|
||||||
|
h1 { font-size: 200%; font-weight: 900; }
|
||||||
|
h2 { font-size: 160%; font-weight: 900; }
|
||||||
|
h3 { font-size: 130%; font-weight: bold; }
|
||||||
|
h4 { font-size: 115%; font-weight: bold; }
|
||||||
|
h5 { font-size: 108%; font-weight: bold; }
|
||||||
|
h6 { font-weight: bold; }
|
||||||
|
|
||||||
|
/* Nom de famille en petites majuscules (uniquement en fran<61>ais) */
|
||||||
|
/* Last names in small caps (for French only) */
|
||||||
|
|
||||||
|
*[class~="surname"]:lang(fr) { font-variant: small-caps; }
|
||||||
|
|
||||||
|
/* Blocs de citation */
|
||||||
|
/* Quotation blocs */
|
||||||
|
|
||||||
|
div[class~="blockquote"] {
|
||||||
|
border: solid 2px #AAA;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[class~="blockquote"] > table {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Blocs lit<69>raux<75>: fond gris clair */
|
||||||
|
/* Literal blocs: light gray background */
|
||||||
|
|
||||||
|
*[class~="literallayout"] {
|
||||||
|
background: #f0f0f0;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Programmes et captures texte<74>: fond bleu clair */
|
||||||
|
/* Listing and text screen snapshots: light blue background */
|
||||||
|
|
||||||
|
*[class~="programlisting"], *[class~="screen"] {
|
||||||
|
background: #f0f0ff;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Les textes <20> remplacer sont surlign<67>s en vert p<>le */
|
||||||
|
/* Replaceable text in highlighted in pale green */
|
||||||
|
|
||||||
|
*[class~="replaceable"] {
|
||||||
|
background-color: #98fb98;
|
||||||
|
font-style: normal; }
|
||||||
|
|
||||||
|
/* Tables<65>: fonds gris clair & bords simples */
|
||||||
|
/* Tables: light gray background and solid borders */
|
||||||
|
|
||||||
|
*[class~="table"] *[class~="title"] { width:100%; border: 0px; }
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-collapse: collapse;
|
||||||
|
padding: 2px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Listes simples en style table */
|
||||||
|
/* Simples lists in table presentation */
|
||||||
|
|
||||||
|
table[class~="simplelist"] {
|
||||||
|
background-color: #F0F0F0;
|
||||||
|
margin: 5px;
|
||||||
|
border: solid 1px #AAA;
|
||||||
|
}
|
||||||
|
|
||||||
|
table[class~="simplelist"] td {
|
||||||
|
border: solid 1px #AAA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Les tables */
|
||||||
|
/* Tables */
|
||||||
|
|
||||||
|
*[class~="table"] table {
|
||||||
|
background-color: #F0F0F0;
|
||||||
|
border: solid 1px #AAA;
|
||||||
|
}
|
||||||
|
*[class~="informaltable"] table { background-color: #F0F0F0; }
|
||||||
|
|
||||||
|
th,td {
|
||||||
|
vertical-align: baseline;
|
||||||
|
text-align: left;
|
||||||
|
padding: 0.1em 0.3em;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alignement des colonnes */
|
||||||
|
/* Colunms alignment */
|
||||||
|
|
||||||
|
td[align=center] , th[align=center] { text-align: center; }
|
||||||
|
td[align=right] , th[align=right] { text-align: right; }
|
||||||
|
td[align=left] , th[align=left] { text-align: left; }
|
||||||
|
td[align=justify] , th[align=justify] { text-align: justify; }
|
||||||
|
|
||||||
|
/* Pas de marge autour des images */
|
||||||
|
/* No inside margins for images */
|
||||||
|
|
||||||
|
img { border: 0; }
|
||||||
|
|
||||||
|
/* Les liens ne sont pas soulign<67>s */
|
||||||
|
/* No underlines for links */
|
||||||
|
|
||||||
|
:link , :visited , :active { text-decoration: none; }
|
||||||
|
|
||||||
|
/* Prudence<63>: cadre jaune et fond jaune clair */
|
||||||
|
/* Caution: yellow border and light yellow background */
|
||||||
|
|
||||||
|
*[class~="caution"] {
|
||||||
|
border: solid 2px yellow;
|
||||||
|
background-color: #ffffe0;
|
||||||
|
padding: 1em 6px 1em ;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[class~="caution"] th {
|
||||||
|
vertical-align: middle
|
||||||
|
}
|
||||||
|
|
||||||
|
*[class~="caution"] table {
|
||||||
|
background-color: #ffffe0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note importante<74>: cadre jaune et fond jaune clair */
|
||||||
|
/* Important: yellow border and light yellow background */
|
||||||
|
|
||||||
|
*[class~="important"] {
|
||||||
|
border: solid 2px yellow;
|
||||||
|
background-color: #ffffe0;
|
||||||
|
padding: 1em 6px 1em;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[class~="important"] th {
|
||||||
|
vertical-align: middle
|
||||||
|
}
|
||||||
|
|
||||||
|
*[class~="important"] table {
|
||||||
|
background-color: #ffffe0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mise en <20>vidence<63>: texte l<>g<EFBFBD>rement plus grand */
|
||||||
|
/* Highlights: slightly larger texts */
|
||||||
|
|
||||||
|
*[class~="highlights"] {
|
||||||
|
font-size: 110%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note<74>: cadre bleu et fond bleu clair */
|
||||||
|
/* Notes: blue border and light blue background */
|
||||||
|
|
||||||
|
*[class~="note"] {
|
||||||
|
border: solid 2px #7099C5;
|
||||||
|
background-color: #f0f0ff;
|
||||||
|
padding: 1em 6px 1em ;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[class~="note"] th {
|
||||||
|
vertical-align: middle
|
||||||
|
}
|
||||||
|
|
||||||
|
*[class~="note"] table {
|
||||||
|
background-color: #f0f0ff;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Astuce<63>: cadre vert et fond vert clair */
|
||||||
|
/* Tip: green border and light green background */
|
||||||
|
|
||||||
|
*[class~="tip"] {
|
||||||
|
border: solid 2px #00ff00;
|
||||||
|
background-color: #f0ffff;
|
||||||
|
padding: 1em 6px 1em ;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[class~="tip"] th {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[class~="tip"] table {
|
||||||
|
background-color: #f0ffff;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avertissement<6E>: cadre rouge et fond rouge clair */
|
||||||
|
/* Warning: red border and light red background */
|
||||||
|
|
||||||
|
*[class~="warning"] {
|
||||||
|
border: solid 2px #ff0000;
|
||||||
|
background-color: #fff0f0;
|
||||||
|
padding: 1em 6px 1em ;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[class~="warning"] th {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*[class~="warning"] table {
|
||||||
|
background-color: #fff0f0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fin */
|
||||||
|
/* The End */
|
||||||
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
# Configuration file for the Sphinx documentation builder.
|
|
||||||
#
|
|
||||||
# This file only contains a selection of the most common options. For a full
|
|
||||||
# list see the documentation:
|
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
||||||
|
|
||||||
# -- Path setup --------------------------------------------------------------
|
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
|
||||||
#
|
|
||||||
# import os
|
|
||||||
# import sys
|
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
current_version = "dev"
|
|
||||||
|
|
||||||
# String used in sidebar
|
|
||||||
version = 'Version: ' + current_version
|
|
||||||
if current_version == 'dev':
|
|
||||||
version = 'Version: Current Development'
|
|
||||||
# Version seen in documentation_options.js and hence in js switchers code
|
|
||||||
release = current_version
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
|
||||||
|
|
||||||
project = 'Bitbake'
|
|
||||||
copyright = '2004-%s, Richard Purdie, Chris Larson, and Phil Blundell' \
|
|
||||||
% datetime.datetime.now().year
|
|
||||||
author = 'Richard Purdie, Chris Larson, and Phil Blundell'
|
|
||||||
|
|
||||||
# external links and substitutions
|
|
||||||
extlinks = {
|
|
||||||
'yocto_docs': ('https://docs.yoctoproject.org%s', None),
|
|
||||||
'oe_lists': ('https://lists.openembedded.org%s', None),
|
|
||||||
}
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
||||||
# ones.
|
|
||||||
extensions = [
|
|
||||||
'sphinx.ext.autosectionlabel',
|
|
||||||
'sphinx.ext.extlinks',
|
|
||||||
]
|
|
||||||
autosectionlabel_prefix_document = True
|
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
|
||||||
templates_path = ['_templates']
|
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
|
||||||
# directories to ignore when looking for source files.
|
|
||||||
# This pattern also affects html_static_path and html_extra_path.
|
|
||||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
|
||||||
|
|
||||||
# master document name. The default changed from contents to index. so better
|
|
||||||
# set it ourselves.
|
|
||||||
master_doc = 'index'
|
|
||||||
|
|
||||||
# create substitution for project configuration variables
|
|
||||||
rst_prolog = """
|
|
||||||
.. |project_name| replace:: %s
|
|
||||||
.. |copyright| replace:: %s
|
|
||||||
.. |author| replace:: %s
|
|
||||||
""" % (project, copyright, author)
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
||||||
# a list of builtin themes.
|
|
||||||
#
|
|
||||||
try:
|
|
||||||
import sphinx_rtd_theme
|
|
||||||
html_theme = 'sphinx_rtd_theme'
|
|
||||||
except ImportError:
|
|
||||||
sys.stderr.write("The Sphinx sphinx_rtd_theme HTML theme was not found.\
|
|
||||||
\nPlease make sure to install the sphinx_rtd_theme python package.\n")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
||||||
html_static_path = ['sphinx-static']
|
|
||||||
|
|
||||||
# Add customm CSS and JS files
|
|
||||||
html_css_files = ['theme_overrides.css']
|
|
||||||
html_js_files = ['switchers.js']
|
|
||||||
|
|
||||||
# Hide 'Created using Sphinx' text
|
|
||||||
html_show_sphinx = False
|
|
||||||
|
|
||||||
# Add 'Last updated' on each page
|
|
||||||
html_last_updated_fmt = '%b %d, %Y'
|
|
||||||
|
|
||||||
# Remove the trailing 'dot' in section numbers
|
|
||||||
html_secnumber_suffix = " "
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
=====
|
|
||||||
Index
|
|
||||||
=====
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: CC-BY-2.5
|
|
||||||
|
|
||||||
===================
|
|
||||||
BitBake User Manual
|
|
||||||
===================
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:caption: Table of Contents
|
|
||||||
:numbered:
|
|
||||||
|
|
||||||
bitbake-user-manual/bitbake-user-manual-intro
|
|
||||||
bitbake-user-manual/bitbake-user-manual-execution
|
|
||||||
bitbake-user-manual/bitbake-user-manual-metadata
|
|
||||||
bitbake-user-manual/bitbake-user-manual-ref-variables-context
|
|
||||||
bitbake-user-manual/bitbake-user-manual-fetching
|
|
||||||
bitbake-user-manual/bitbake-user-manual-ref-variables
|
|
||||||
bitbake-user-manual/bitbake-user-manual-hello
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
:hidden:
|
|
||||||
|
|
||||||
genindex
|
|
||||||
releases
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
.. include:: <xhtml1-lat1.txt>
|
|
||||||
|
|
||||||
| BitBake Community
|
|
||||||
| Copyright |copy| |copyright|
|
|
||||||
| <bitbake-devel@lists.openembedded.org>
|
|
||||||
|
|
||||||
This work is licensed under the Creative Commons Attribution License. To view a
|
|
||||||
copy of this license, visit http://creativecommons.org/licenses/by/2.5/ or send
|
|
||||||
a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View,
|
|
||||||
California 94041, USA.
|
|
||||||
51
bitbake/doc/poky.ent
Normal file
51
bitbake/doc/poky.ent
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!ENTITY DISTRO "1.4">
|
||||||
|
<!ENTITY DISTRO_NAME "tbd">
|
||||||
|
<!ENTITY YOCTO_DOC_VERSION "1.4">
|
||||||
|
<!ENTITY POKYVERSION "8.0">
|
||||||
|
<!ENTITY YOCTO_POKY "poky-&DISTRO_NAME;-&POKYVERSION;">
|
||||||
|
<!ENTITY COPYRIGHT_YEAR "2010-2013">
|
||||||
|
<!ENTITY YOCTO_DL_URL "http://downloads.yoctoproject.org">
|
||||||
|
<!ENTITY YOCTO_HOME_URL "http://www.yoctoproject.org">
|
||||||
|
<!ENTITY YOCTO_LISTS_URL "http://lists.yoctoproject.org">
|
||||||
|
<!ENTITY YOCTO_BUGZILLA_URL "http://bugzilla.yoctoproject.org">
|
||||||
|
<!ENTITY YOCTO_WIKI_URL "https://wiki.yoctoproject.org">
|
||||||
|
<!ENTITY YOCTO_AB_URL "http://autobuilder.yoctoproject.org">
|
||||||
|
<!ENTITY YOCTO_GIT_URL "http://git.yoctoproject.org">
|
||||||
|
<!ENTITY YOCTO_ADTREPO_URL "http://adtrepo.yoctoproject.org">
|
||||||
|
<!ENTITY OE_HOME_URL "http://www.openembedded.org">
|
||||||
|
<!ENTITY OE_LISTS_URL "http://lists.linuxtogo.org/cgi-bin/mailman">
|
||||||
|
<!ENTITY OE_DOCS_URL "http://docs.openembedded.org">
|
||||||
|
<!ENTITY OH_HOME_URL "http://o-hand.com">
|
||||||
|
<!ENTITY BITBAKE_HOME_URL "http://developer.berlios.de/projects/bitbake/">
|
||||||
|
<!ENTITY YOCTO_DOCS_URL "&YOCTO_HOME_URL;/docs">
|
||||||
|
<!ENTITY YOCTO_SOURCES_URL "&YOCTO_HOME_URL;/sources/">
|
||||||
|
<!ENTITY YOCTO_AB_PORT_URL "&YOCTO_AB_URL;:8010">
|
||||||
|
<!ENTITY YOCTO_AB_NIGHTLY_URL "&YOCTO_AB_URL;/nightly/">
|
||||||
|
<!ENTITY YOCTO_POKY_URL "&YOCTO_DL_URL;/releases/poky/">
|
||||||
|
<!ENTITY YOCTO_RELEASE_DL_URL "&YOCTO_DL_URL;/releases/yocto/yocto-&DISTRO;">
|
||||||
|
<!ENTITY YOCTO_TOOLCHAIN_DL_URL "&YOCTO_RELEASE_DL_URL;/toolchain/">
|
||||||
|
<!ENTITY YOCTO_ADTINSTALLER_DL_URL "&YOCTO_RELEASE_DL_URL;/adt_installer">
|
||||||
|
<!ENTITY YOCTO_POKY_DL_URL "&YOCTO_RELEASE_DL_URL;/&YOCTO_POKY;.tar.bz2">
|
||||||
|
<!ENTITY YOCTO_MACHINES_DL_URL "&YOCTO_RELEASE_DL_URL;/machines">
|
||||||
|
<!ENTITY YOCTO_QEMU_DL_URL "&YOCTO_MACHINES_DL_URL;/qemu">
|
||||||
|
<!ENTITY YOCTO_PYTHON-i686_DL_URL "&YOCTO_DL_URL;/releases/miscsupport/python-nativesdk-standalone-i686.tar.bz2">
|
||||||
|
<!ENTITY YOCTO_PYTHON-x86_64_DL_URL "&YOCTO_DL_URL;/releases/miscsupport/python-nativesdk-standalone-x86_64.tar.bz2">
|
||||||
|
<!ENTITY YOCTO_DOCS_QS_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/yocto-project-qs/yocto-project-qs.html">
|
||||||
|
<!ENTITY YOCTO_DOCS_ADT_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/adt-manual/adt-manual.html">
|
||||||
|
<!ENTITY YOCTO_DOCS_REF_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/ref-manual/ref-manual.html">
|
||||||
|
<!ENTITY YOCTO_DOCS_BSP_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/bsp-guide/bsp-guide.html">
|
||||||
|
<!ENTITY YOCTO_DOCS_DEV_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/dev-manual/dev-manual.html">
|
||||||
|
<!ENTITY YOCTO_DOCS_KERNEL_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/kernel-manual/kernel-manual.html">
|
||||||
|
<!ENTITY YOCTO_ADTPATH_DIR "/opt/poky/&DISTRO;">
|
||||||
|
<!ENTITY YOCTO_POKY_TARBALL "&YOCTO_POKY;.tar.bz2">
|
||||||
|
<!ENTITY OE_INIT_PATH "&YOCTO_POKY;/oe-init-build-env">
|
||||||
|
<!ENTITY OE_INIT_FILE "oe-init-build-env">
|
||||||
|
<!ENTITY UBUNTU_HOST_PACKAGES_ESSENTIAL "gawk wget git-core diffstat unzip texinfo \
|
||||||
|
build-essential chrpath">
|
||||||
|
<!ENTITY FEDORA_HOST_PACKAGES_ESSENTIAL "gawk make wget tar bzip2 gzip python unzip perl patch \
|
||||||
|
diffutils diffstat git cpp gcc gcc-c++ eglibc-devel texinfo chrpath \
|
||||||
|
ccache">
|
||||||
|
<!ENTITY OPENSUSE_HOST_PACKAGES_ESSENTIAL "python gcc gcc-c++ git chrpath make wget python-xml \
|
||||||
|
diffstat texinfo python-curses">
|
||||||
|
<!ENTITY CENTOS_HOST_PACKAGES_ESSENTIAL "gawk make wget tar bzip2 gzip python unzip perl patch \
|
||||||
|
diffutils diffstat git cpp gcc gcc-c++ glibc-devel texinfo chrpath">
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: CC-BY-2.5
|
|
||||||
|
|
||||||
=================================
|
|
||||||
BitBake Supported Release Manuals
|
|
||||||
=================================
|
|
||||||
|
|
||||||
*******************************
|
|
||||||
Release Series 4.2 (mickledore)
|
|
||||||
*******************************
|
|
||||||
|
|
||||||
- :yocto_docs:`BitBake 2.4 User Manual </bitbake/2.4/>`
|
|
||||||
|
|
||||||
******************************
|
|
||||||
Release Series 4.0 (kirkstone)
|
|
||||||
******************************
|
|
||||||
|
|
||||||
- :yocto_docs:`BitBake 2.0 User Manual </bitbake/2.0/>`
|
|
||||||
|
|
||||||
****************************
|
|
||||||
Release Series 3.1 (dunfell)
|
|
||||||
****************************
|
|
||||||
|
|
||||||
- :yocto_docs:`BitBake 1.46 User Manual </bitbake/1.46/>`
|
|
||||||
|
|
||||||
================================
|
|
||||||
BitBake Outdated Release Manuals
|
|
||||||
================================
|
|
||||||
|
|
||||||
*****************************
|
|
||||||
Release Series 4.1 (langdale)
|
|
||||||
*****************************
|
|
||||||
|
|
||||||
- :yocto_docs:`BitBake 2.2 User Manual </bitbake/2.2/>`
|
|
||||||
|
|
||||||
******************************
|
|
||||||
Release Series 3.4 (honister)
|
|
||||||
******************************
|
|
||||||
|
|
||||||
- :yocto_docs:`BitBake 1.52 User Manual </bitbake/1.52/>`
|
|
||||||
|
|
||||||
******************************
|
|
||||||
Release Series 3.3 (hardknott)
|
|
||||||
******************************
|
|
||||||
|
|
||||||
- :yocto_docs:`BitBake 1.50 User Manual </bitbake/1.50/>`
|
|
||||||
|
|
||||||
*******************************
|
|
||||||
Release Series 3.2 (gatesgarth)
|
|
||||||
*******************************
|
|
||||||
|
|
||||||
- :yocto_docs:`BitBake 1.48 User Manual </bitbake/1.48/>`
|
|
||||||
|
|
||||||
*******************************************
|
|
||||||
Release Series 3.1 (dunfell first versions)
|
|
||||||
*******************************************
|
|
||||||
|
|
||||||
- :yocto_docs:`3.1 BitBake User Manual </3.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`3.1.1 BitBake User Manual </3.1.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`3.1.2 BitBake User Manual </3.1.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`3.1.3 BitBake User Manual </3.1.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
*************************
|
|
||||||
Release Series 3.0 (zeus)
|
|
||||||
*************************
|
|
||||||
|
|
||||||
- :yocto_docs:`3.0 BitBake User Manual </3.0/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`3.0.1 BitBake User Manual </3.0.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`3.0.2 BitBake User Manual </3.0.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`3.0.3 BitBake User Manual </3.0.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`3.0.4 BitBake User Manual </3.0.4/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
****************************
|
|
||||||
Release Series 2.7 (warrior)
|
|
||||||
****************************
|
|
||||||
|
|
||||||
- :yocto_docs:`2.7 BitBake User Manual </2.7/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.7.1 BitBake User Manual </2.7.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.7.2 BitBake User Manual </2.7.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.7.3 BitBake User Manual </2.7.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.7.4 BitBake User Manual </2.7.4/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
*************************
|
|
||||||
Release Series 2.6 (thud)
|
|
||||||
*************************
|
|
||||||
|
|
||||||
- :yocto_docs:`2.6 BitBake User Manual </2.6/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.6.1 BitBake User Manual </2.6.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.6.2 BitBake User Manual </2.6.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.6.3 BitBake User Manual </2.6.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.6.4 BitBake User Manual </2.6.4/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
*************************
|
|
||||||
Release Series 2.5 (sumo)
|
|
||||||
*************************
|
|
||||||
|
|
||||||
- :yocto_docs:`2.5 Documentation </2.5>`
|
|
||||||
- :yocto_docs:`2.5.1 Documentation </2.5.1>`
|
|
||||||
- :yocto_docs:`2.5.2 Documentation </2.5.2>`
|
|
||||||
- :yocto_docs:`2.5.3 Documentation </2.5.3>`
|
|
||||||
|
|
||||||
**************************
|
|
||||||
Release Series 2.4 (rocko)
|
|
||||||
**************************
|
|
||||||
|
|
||||||
- :yocto_docs:`2.4 BitBake User Manual </2.4/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.4.1 BitBake User Manual </2.4.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.4.2 BitBake User Manual </2.4.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.4.3 BitBake User Manual </2.4.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.4.4 BitBake User Manual </2.4.4/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
*************************
|
|
||||||
Release Series 2.3 (pyro)
|
|
||||||
*************************
|
|
||||||
|
|
||||||
- :yocto_docs:`2.3 BitBake User Manual </2.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.3.1 BitBake User Manual </2.3.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.3.2 BitBake User Manual </2.3.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.3.3 BitBake User Manual </2.3.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.3.4 BitBake User Manual </2.3.4/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
**************************
|
|
||||||
Release Series 2.2 (morty)
|
|
||||||
**************************
|
|
||||||
|
|
||||||
- :yocto_docs:`2.2 BitBake User Manual </2.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.2.1 BitBake User Manual </2.2.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.2.2 BitBake User Manual </2.2.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.2.3 BitBake User Manual </2.2.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
****************************
|
|
||||||
Release Series 2.1 (krogoth)
|
|
||||||
****************************
|
|
||||||
|
|
||||||
- :yocto_docs:`2.1 BitBake User Manual </2.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.1.1 BitBake User Manual </2.1.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.1.2 BitBake User Manual </2.1.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.1.3 BitBake User Manual </2.1.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
***************************
|
|
||||||
Release Series 2.0 (jethro)
|
|
||||||
***************************
|
|
||||||
|
|
||||||
- :yocto_docs:`1.9 BitBake User Manual </1.9/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.0 BitBake User Manual </2.0/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.0.1 BitBake User Manual </2.0.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.0.2 BitBake User Manual </2.0.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`2.0.3 BitBake User Manual </2.0.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
*************************
|
|
||||||
Release Series 1.8 (fido)
|
|
||||||
*************************
|
|
||||||
|
|
||||||
- :yocto_docs:`1.8 BitBake User Manual </1.8/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`1.8.1 BitBake User Manual </1.8.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`1.8.2 BitBake User Manual </1.8.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
**************************
|
|
||||||
Release Series 1.7 (dizzy)
|
|
||||||
**************************
|
|
||||||
|
|
||||||
- :yocto_docs:`1.7 BitBake User Manual </1.7/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`1.7.1 BitBake User Manual </1.7.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`1.7.2 BitBake User Manual </1.7.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`1.7.3 BitBake User Manual </1.7.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
**************************
|
|
||||||
Release Series 1.6 (daisy)
|
|
||||||
**************************
|
|
||||||
|
|
||||||
- :yocto_docs:`1.6 BitBake User Manual </1.6/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`1.6.1 BitBake User Manual </1.6.1/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`1.6.2 BitBake User Manual </1.6.2/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
- :yocto_docs:`1.6.3 BitBake User Manual </1.6.3/bitbake-user-manual/bitbake-user-manual.html>`
|
|
||||||
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var all_versions = {
|
|
||||||
'dev': 'dev (3.2)',
|
|
||||||
'3.1.2': '3.1.2',
|
|
||||||
'3.0.3': '3.0.3',
|
|
||||||
'2.7.4': '2.7.4',
|
|
||||||
};
|
|
||||||
|
|
||||||
var all_doctypes = {
|
|
||||||
'single': 'Individual Webpages',
|
|
||||||
'mega': "All-in-one 'Mega' Manual",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Simple version comparision
|
|
||||||
// Return 1 if a > b
|
|
||||||
// Return -1 if a < b
|
|
||||||
// Return 0 if a == b
|
|
||||||
function ver_compare(a, b) {
|
|
||||||
if (a == "dev") {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a === b) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var a_components = a.split(".");
|
|
||||||
var b_components = b.split(".");
|
|
||||||
|
|
||||||
var len = Math.min(a_components.length, b_components.length);
|
|
||||||
|
|
||||||
// loop while the components are equal
|
|
||||||
for (var i = 0; i < len; i++) {
|
|
||||||
// A bigger than B
|
|
||||||
if (parseInt(a_components[i]) > parseInt(b_components[i])) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// B bigger than A
|
|
||||||
if (parseInt(a_components[i]) < parseInt(b_components[i])) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If one's a prefix of the other, the longer one is greater.
|
|
||||||
if (a_components.length > b_components.length) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a_components.length < b_components.length) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise they are the same.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_version_select(current_series, current_version) {
|
|
||||||
var buf = ['<select>'];
|
|
||||||
|
|
||||||
$.each(all_versions, function(version, title) {
|
|
||||||
var series = version.substr(0, 3);
|
|
||||||
if (series == current_series) {
|
|
||||||
if (version == current_version)
|
|
||||||
buf.push('<option value="' + version + '" selected="selected">' + title + '</option>');
|
|
||||||
else
|
|
||||||
buf.push('<option value="' + version + '">' + title + '</option>');
|
|
||||||
|
|
||||||
if (version != current_version)
|
|
||||||
buf.push('<option value="' + current_version + '" selected="selected">' + current_version + '</option>');
|
|
||||||
} else {
|
|
||||||
buf.push('<option value="' + version + '">' + title + '</option>');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
buf.push('</select>');
|
|
||||||
return buf.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_doctype_select(current_doctype) {
|
|
||||||
var buf = ['<select>'];
|
|
||||||
|
|
||||||
$.each(all_doctypes, function(doctype, title) {
|
|
||||||
if (doctype == current_doctype)
|
|
||||||
buf.push('<option value="' + doctype + '" selected="selected">' +
|
|
||||||
all_doctypes[current_doctype] + '</option>');
|
|
||||||
else
|
|
||||||
buf.push('<option value="' + doctype + '">' + title + '</option>');
|
|
||||||
});
|
|
||||||
if (!(current_doctype in all_doctypes)) {
|
|
||||||
// In case we're browsing a doctype that is not yet in all_doctypes.
|
|
||||||
buf.push('<option value="' + current_doctype + '" selected="selected">' +
|
|
||||||
current_doctype + '</option>');
|
|
||||||
all_doctypes[current_doctype] = current_doctype;
|
|
||||||
}
|
|
||||||
buf.push('</select>');
|
|
||||||
return buf.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigate_to_first_existing(urls) {
|
|
||||||
// Navigate to the first existing URL in urls.
|
|
||||||
var url = urls.shift();
|
|
||||||
|
|
||||||
// Web browsers won't redirect file:// urls to file urls using ajax but
|
|
||||||
// its useful for local testing
|
|
||||||
if (url.startsWith("file://")) {
|
|
||||||
window.location.href = url;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urls.length == 0) {
|
|
||||||
window.location.href = url;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
url: url,
|
|
||||||
success: function() {
|
|
||||||
window.location.href = url;
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
navigate_to_first_existing(urls);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_docroot_url() {
|
|
||||||
var url = window.location.href;
|
|
||||||
var root = DOCUMENTATION_OPTIONS.URL_ROOT;
|
|
||||||
|
|
||||||
var urlarray = url.split('/');
|
|
||||||
// Trim off anything after '/'
|
|
||||||
urlarray.pop();
|
|
||||||
var depth = (root.match(/\.\.\//g) || []).length;
|
|
||||||
for (var i = 0; i < depth; i++) {
|
|
||||||
urlarray.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
return urlarray.join('/') + '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
function on_version_switch() {
|
|
||||||
var selected_version = $(this).children('option:selected').attr('value');
|
|
||||||
var url = window.location.href;
|
|
||||||
var current_version = DOCUMENTATION_OPTIONS.VERSION;
|
|
||||||
var docroot = get_docroot_url()
|
|
||||||
|
|
||||||
var new_versionpath = selected_version + '/';
|
|
||||||
if (selected_version == "dev")
|
|
||||||
new_versionpath = '';
|
|
||||||
|
|
||||||
// dev versions have no version prefix
|
|
||||||
if (current_version == "dev") {
|
|
||||||
var new_url = docroot + new_versionpath + url.replace(docroot, "");
|
|
||||||
var fallback_url = docroot + new_versionpath;
|
|
||||||
} else {
|
|
||||||
var new_url = url.replace('/' + current_version + '/', '/' + new_versionpath);
|
|
||||||
var fallback_url = new_url.replace(url.replace(docroot, ""), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(get_docroot_url())
|
|
||||||
console.log(url + " to url " + new_url);
|
|
||||||
console.log(url + " to fallback " + fallback_url);
|
|
||||||
|
|
||||||
if (new_url != url) {
|
|
||||||
navigate_to_first_existing([
|
|
||||||
new_url,
|
|
||||||
fallback_url,
|
|
||||||
'https://www.yoctoproject.org/docs/',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function on_doctype_switch() {
|
|
||||||
var selected_doctype = $(this).children('option:selected').attr('value');
|
|
||||||
var url = window.location.href;
|
|
||||||
if (selected_doctype == 'mega') {
|
|
||||||
var docroot = get_docroot_url()
|
|
||||||
var current_version = DOCUMENTATION_OPTIONS.VERSION;
|
|
||||||
// Assume manuals before 3.2 are using old docbook mega-manual
|
|
||||||
if (ver_compare(current_version, "3.2") < 0) {
|
|
||||||
var new_url = docroot + "mega-manual/mega-manual.html";
|
|
||||||
} else {
|
|
||||||
var new_url = docroot + "singleindex.html";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var new_url = url.replace("singleindex.html", "index.html")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_url != url) {
|
|
||||||
navigate_to_first_existing([
|
|
||||||
new_url,
|
|
||||||
'https://www.yoctoproject.org/docs/',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the current doctype based upon the url
|
|
||||||
function doctype_segment_from_url(url) {
|
|
||||||
if (url.includes("singleindex") || url.includes("mega-manual"))
|
|
||||||
return "mega";
|
|
||||||
return "single";
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
var release = DOCUMENTATION_OPTIONS.VERSION;
|
|
||||||
var current_doctype = doctype_segment_from_url(window.location.href);
|
|
||||||
var current_series = release.substr(0, 3);
|
|
||||||
var version_select = build_version_select(current_series, release);
|
|
||||||
|
|
||||||
$('.version_switcher_placeholder').html(version_select);
|
|
||||||
$('.version_switcher_placeholder select').bind('change', on_version_switch);
|
|
||||||
|
|
||||||
var doctype_select = build_doctype_select(current_doctype);
|
|
||||||
|
|
||||||
$('.doctype_switcher_placeholder').html(doctype_select);
|
|
||||||
$('.doctype_switcher_placeholder select').bind('change', on_doctype_switch);
|
|
||||||
|
|
||||||
if (ver_compare(release, "3.1") < 0) {
|
|
||||||
$('#outdated-warning').html('Version ' + release + ' of the project is now considered obsolete, please select and use a more recent version');
|
|
||||||
$('#outdated-warning').css('padding', '.5em');
|
|
||||||
} else if (release != "dev") {
|
|
||||||
$.each(all_versions, function(version, title) {
|
|
||||||
var series = version.substr(0, 3);
|
|
||||||
if (series == current_series && version != release) {
|
|
||||||
$('#outdated-warning').html('This document is for outdated version ' + release + ', you should select the latest release version in this series, ' + version + '.');
|
|
||||||
$('#outdated-warning').css('padding', '.5em');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
/*
|
|
||||||
SPDX-License-Identifier: CC-BY-2.0-UK
|
|
||||||
*/
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: Verdana, Sans, sans-serif;
|
|
||||||
margin: 0em auto;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,h2,h3,h4,h5,h6,h7 {
|
|
||||||
font-family: Arial, Sans;
|
|
||||||
color: #00557D;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2em;
|
|
||||||
text-align: left;
|
|
||||||
padding: 0em 0em 0em 0em;
|
|
||||||
margin: 2em 0em 0em 0em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2.subtitle {
|
|
||||||
margin: 0.10em 0em 3.0em 0em;
|
|
||||||
padding: 0em 0em 0em 0em;
|
|
||||||
font-size: 1.8em;
|
|
||||||
padding-left: 20%;
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 2em 0em 0.66em 0em;
|
|
||||||
padding: 0.5em 0em 0em 0em;
|
|
||||||
font-size: 1.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3.subtitle {
|
|
||||||
margin: 0em 0em 1em 0em;
|
|
||||||
padding: 0em 0em 0em 0em;
|
|
||||||
font-size: 142.14%;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 1em 0em 0.5em 0em;
|
|
||||||
padding: 1em 0em 0em 0em;
|
|
||||||
font-size: 140%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin: 1em 0em 0.5em 0em;
|
|
||||||
padding: 1em 0em 0em 0em;
|
|
||||||
font-size: 120%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
margin: 1em 0em 0.5em 0em;
|
|
||||||
padding: 1em 0em 0em 0em;
|
|
||||||
font-size: 110%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
h6 {
|
|
||||||
margin: 1em 0em 0em 0em;
|
|
||||||
padding: 1em 0em 0em 0em;
|
|
||||||
font-size: 110%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
em {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pre {
|
|
||||||
font-size: medium;
|
|
||||||
font-family: Courier, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wy-nav-content a {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: #444;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wy-nav-content a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
background-color: #dedede;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wy-nav-content a:visited {
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
[alt='Permalink'] { color: #eee; }
|
|
||||||
[alt='Permalink']:hover { color: black; }
|
|
||||||
|
|
||||||
@media screen {
|
|
||||||
/* content column
|
|
||||||
*
|
|
||||||
* RTD theme's default is 800px as max width for the content, but we have
|
|
||||||
* tables with tons of columns, which need the full width of the view-port.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.wy-nav-content{max-width: none; }
|
|
||||||
|
|
||||||
/* inline literal: drop the borderbox, padding and red color */
|
|
||||||
code, .rst-content tt, .rst-content code {
|
|
||||||
color: inherit;
|
|
||||||
border: none;
|
|
||||||
padding: unset;
|
|
||||||
background: inherit;
|
|
||||||
font-size: 85%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Admonition should be gray, not blue or green */
|
|
||||||
.rst-content .note .admonition-title,
|
|
||||||
.rst-content .tip .admonition-title,
|
|
||||||
.rst-content .warning .admonition-title,
|
|
||||||
.rst-content .caution .admonition-title,
|
|
||||||
.rst-content .important .admonition-title {
|
|
||||||
background: #f0f0f2;
|
|
||||||
color: #00557D;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.rst-content .note,
|
|
||||||
.rst-content .tip,
|
|
||||||
.rst-content .important,
|
|
||||||
.rst-content .warning,
|
|
||||||
.rst-content .caution {
|
|
||||||
background: #f0f0f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove the icon in front of note/tip element, and before the logo */
|
|
||||||
.icon-home:before, .rst-content .admonition-title:before {
|
|
||||||
display: none
|
|
||||||
}
|
|
||||||
|
|
||||||
/* a custom informalexample container is used in some doc */
|
|
||||||
.informalexample {
|
|
||||||
border: 1px solid;
|
|
||||||
border-color: #aaa;
|
|
||||||
margin: 1em 0em;
|
|
||||||
padding: 1em;
|
|
||||||
page-break-inside: avoid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove the blue background in the top left corner, around the logo */
|
|
||||||
.wy-side-nav-search {
|
|
||||||
background: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
1
bitbake/doc/template/Vera.xml
vendored
Normal file
1
bitbake/doc/template/Vera.xml
vendored
Normal file
File diff suppressed because one or more lines are too long
1
bitbake/doc/template/VeraMoBd.xml
vendored
Normal file
1
bitbake/doc/template/VeraMoBd.xml
vendored
Normal file
File diff suppressed because one or more lines are too long
1
bitbake/doc/template/VeraMono.xml
vendored
Normal file
1
bitbake/doc/template/VeraMono.xml
vendored
Normal file
File diff suppressed because one or more lines are too long
39
bitbake/doc/template/component.title.xsl
vendored
Normal file
39
bitbake/doc/template/component.title.xsl
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:d="http://docbook.org/ns/docbook"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
exclude-result-prefixes="d">
|
||||||
|
|
||||||
|
<xsl:template name="component.title">
|
||||||
|
<xsl:param name="node" select="."/>
|
||||||
|
|
||||||
|
<xsl:variable name="level">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="ancestor::d:section">
|
||||||
|
<xsl:value-of select="count(ancestor::d:section)+1"/>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:when test="ancestor::d:sect5">6</xsl:when>
|
||||||
|
<xsl:when test="ancestor::d:sect4">5</xsl:when>
|
||||||
|
<xsl:when test="ancestor::d:sect3">4</xsl:when>
|
||||||
|
<xsl:when test="ancestor::d:sect2">3</xsl:when>
|
||||||
|
<xsl:when test="ancestor::d:sect1">2</xsl:when>
|
||||||
|
<xsl:otherwise>1</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:variable>
|
||||||
|
<xsl:element name="h{$level+1}" namespace="http://www.w3.org/1999/xhtml">
|
||||||
|
<xsl:attribute name="class">title</xsl:attribute>
|
||||||
|
<xsl:if test="$generate.id.attributes = 0">
|
||||||
|
<xsl:call-template name="anchor">
|
||||||
|
<xsl:with-param name="node" select="$node"/>
|
||||||
|
<xsl:with-param name="conditional" select="0"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:apply-templates select="$node" mode="object.title.markup">
|
||||||
|
<xsl:with-param name="allow-anchors" select="1"/>
|
||||||
|
</xsl:apply-templates>
|
||||||
|
<xsl:call-template name="permalink">
|
||||||
|
<xsl:with-param name="node" select="$node"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
||||||
64
bitbake/doc/template/db-pdf.xsl
vendored
Normal file
64
bitbake/doc/template/db-pdf.xsl
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version='1.0'?>
|
||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
|
||||||
|
|
||||||
|
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl" />
|
||||||
|
|
||||||
|
<!-- check project-plan.sh for how this is generated, needed to tweak
|
||||||
|
the cover page
|
||||||
|
-->
|
||||||
|
<xsl:include href="/tmp/titlepage.xsl"/>
|
||||||
|
|
||||||
|
<!-- To force a page break in document, i.e per section add a
|
||||||
|
<?hard-pagebreak?> tag.
|
||||||
|
-->
|
||||||
|
<xsl:template match="processing-instruction('hard-pagebreak')">
|
||||||
|
<fo:block break-before='page' />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--Fix for defualt indent getting TOC all wierd..
|
||||||
|
See http://sources.redhat.com/ml/docbook-apps/2005-q1/msg00455.html
|
||||||
|
FIXME: must be a better fix
|
||||||
|
-->
|
||||||
|
<xsl:param name="body.start.indent" select="'0'"/>
|
||||||
|
<!--<xsl:param name="title.margin.left" select="'0'"/>-->
|
||||||
|
|
||||||
|
<!-- stop long-ish header titles getting wrapped -->
|
||||||
|
<xsl:param name="header.column.widths">1 10 1</xsl:param>
|
||||||
|
|
||||||
|
<!-- customise headers and footers a little -->
|
||||||
|
|
||||||
|
<xsl:template name="head.sep.rule">
|
||||||
|
<xsl:if test="$header.rule != 0">
|
||||||
|
<xsl:attribute name="border-bottom-width">0.5pt</xsl:attribute>
|
||||||
|
<xsl:attribute name="border-bottom-style">solid</xsl:attribute>
|
||||||
|
<xsl:attribute name="border-bottom-color">#cccccc</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="foot.sep.rule">
|
||||||
|
<xsl:if test="$footer.rule != 0">
|
||||||
|
<xsl:attribute name="border-top-width">0.5pt</xsl:attribute>
|
||||||
|
<xsl:attribute name="border-top-style">solid</xsl:attribute>
|
||||||
|
<xsl:attribute name="border-top-color">#cccccc</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:attribute-set name="header.content.properties">
|
||||||
|
<xsl:attribute name="color">#cccccc</xsl:attribute>
|
||||||
|
</xsl:attribute-set>
|
||||||
|
|
||||||
|
<xsl:attribute-set name="footer.content.properties">
|
||||||
|
<xsl:attribute name="color">#cccccc</xsl:attribute>
|
||||||
|
</xsl:attribute-set>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- general settings -->
|
||||||
|
|
||||||
|
<xsl:param name="fop1.extensions" select="1"></xsl:param>
|
||||||
|
<xsl:param name="paper.type" select="'A4'"></xsl:param>
|
||||||
|
<xsl:param name="section.autolabel" select="1"></xsl:param>
|
||||||
|
<xsl:param name="body.font.family" select="'verasans'"></xsl:param>
|
||||||
|
<xsl:param name="title.font.family" select="'verasans'"></xsl:param>
|
||||||
|
<xsl:param name="monospace.font.family" select="'veramono'"></xsl:param>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
25
bitbake/doc/template/division.title.xsl
vendored
Normal file
25
bitbake/doc/template/division.title.xsl
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:d="http://docbook.org/ns/docbook"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
exclude-result-prefixes="d">
|
||||||
|
|
||||||
|
<xsl:template name="division.title">
|
||||||
|
<xsl:param name="node" select="."/>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
<xsl:attribute name="class">title</xsl:attribute>
|
||||||
|
<xsl:call-template name="anchor">
|
||||||
|
<xsl:with-param name="node" select="$node"/>
|
||||||
|
<xsl:with-param name="conditional" select="0"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
<xsl:apply-templates select="$node" mode="object.title.markup">
|
||||||
|
<xsl:with-param name="allow-anchors" select="1"/>
|
||||||
|
</xsl:apply-templates>
|
||||||
|
<xsl:call-template name="permalink">
|
||||||
|
<xsl:with-param name="node" select="$node"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</h1>
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
||||||
58
bitbake/doc/template/fop-config.xml
vendored
Normal file
58
bitbake/doc/template/fop-config.xml
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<fop version="1.0">
|
||||||
|
|
||||||
|
<!-- Strict user configuration -->
|
||||||
|
<strict-configuration>true</strict-configuration>
|
||||||
|
|
||||||
|
<!-- Strict FO validation -->
|
||||||
|
<strict-validation>true</strict-validation>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Set the baseDir so common/openedhand.svg references in plans still
|
||||||
|
work ok. Note, relative file references to current dir should still work.
|
||||||
|
-->
|
||||||
|
<base>../template</base>
|
||||||
|
<font-base>../template</font-base>
|
||||||
|
|
||||||
|
<!-- Source resolution in dpi (dots/pixels per inch) for determining the
|
||||||
|
size of pixels in SVG and bitmap images, default: 72dpi -->
|
||||||
|
<!-- <source-resolution>72</source-resolution> -->
|
||||||
|
<!-- Target resolution in dpi (dots/pixels per inch) for specifying the
|
||||||
|
target resolution for generated bitmaps, default: 72dpi -->
|
||||||
|
<!-- <target-resolution>72</target-resolution> -->
|
||||||
|
|
||||||
|
<!-- default page-height and page-width, in case
|
||||||
|
value is specified as auto -->
|
||||||
|
<default-page-settings height="11in" width="8.26in"/>
|
||||||
|
|
||||||
|
<!-- <use-cache>false</use-cache> -->
|
||||||
|
|
||||||
|
<renderers>
|
||||||
|
<renderer mime="application/pdf">
|
||||||
|
<fonts>
|
||||||
|
<font metrics-file="VeraMono.xml"
|
||||||
|
kerning="yes"
|
||||||
|
embed-url="VeraMono.ttf">
|
||||||
|
<font-triplet name="veramono" style="normal" weight="normal"/>
|
||||||
|
</font>
|
||||||
|
|
||||||
|
<font metrics-file="VeraMoBd.xml"
|
||||||
|
kerning="yes"
|
||||||
|
embed-url="VeraMoBd.ttf">
|
||||||
|
<font-triplet name="veramono" style="normal" weight="bold"/>
|
||||||
|
</font>
|
||||||
|
|
||||||
|
<font metrics-file="Vera.xml"
|
||||||
|
kerning="yes"
|
||||||
|
embed-url="Vera.ttf">
|
||||||
|
<font-triplet name="verasans" style="normal" weight="normal"/>
|
||||||
|
<font-triplet name="verasans" style="normal" weight="bold"/>
|
||||||
|
<font-triplet name="verasans" style="italic" weight="normal"/>
|
||||||
|
<font-triplet name="verasans" style="italic" weight="bold"/>
|
||||||
|
</font>
|
||||||
|
|
||||||
|
<auto-detect/>
|
||||||
|
</fonts>
|
||||||
|
</renderer>
|
||||||
|
</renderers>
|
||||||
|
</fop>
|
||||||
|
|
||||||
21
bitbake/doc/template/formal.object.heading.xsl
vendored
Normal file
21
bitbake/doc/template/formal.object.heading.xsl
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:d="http://docbook.org/ns/docbook"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
exclude-result-prefixes="d">
|
||||||
|
|
||||||
|
<xsl:template name="formal.object.heading">
|
||||||
|
<xsl:param name="object" select="."/>
|
||||||
|
<xsl:param name="title">
|
||||||
|
<xsl:apply-templates select="$object" mode="object.title.markup">
|
||||||
|
<xsl:with-param name="allow-anchors" select="1"/>
|
||||||
|
</xsl:apply-templates>
|
||||||
|
</xsl:param>
|
||||||
|
<p class="title">
|
||||||
|
<b><xsl:copy-of select="$title"/></b>
|
||||||
|
<xsl:call-template name="permalink">
|
||||||
|
<xsl:with-param name="node" select="$object"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</p>
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
||||||
14
bitbake/doc/template/gloss-permalinks.xsl
vendored
Normal file
14
bitbake/doc/template/gloss-permalinks.xsl
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:d="http://docbook.org/ns/docbook"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
|
||||||
|
<xsl:template match="glossentry/glossterm">
|
||||||
|
<xsl:apply-imports/>
|
||||||
|
<xsl:if test="$generate.permalink != 0">
|
||||||
|
<xsl:call-template name="permalink">
|
||||||
|
<xsl:with-param name="node" select=".."/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
||||||
25
bitbake/doc/template/permalinks.xsl
vendored
Normal file
25
bitbake/doc/template/permalinks.xsl
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||||
|
|
||||||
|
<xsl:param name="generate.permalink" select="1"/>
|
||||||
|
<xsl:param name="permalink.text">¶</xsl:param>
|
||||||
|
|
||||||
|
<xsl:template name="permalink">
|
||||||
|
<xsl:param name="node"/>
|
||||||
|
|
||||||
|
<xsl:if test="$generate.permalink != '0'">
|
||||||
|
<span class="permalink">
|
||||||
|
<a alt="Permalink" title="Permalink">
|
||||||
|
<xsl:attribute name="href">
|
||||||
|
<xsl:call-template name="href.target">
|
||||||
|
<xsl:with-param name="object" select="$node"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:copy-of select="$permalink.text"/>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
||||||
55
bitbake/doc/template/section.title.xsl
vendored
Normal file
55
bitbake/doc/template/section.title.xsl
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:d="http://docbook.org/ns/docbook"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="d">
|
||||||
|
|
||||||
|
<xsl:template name="section.title">
|
||||||
|
<xsl:variable name="section"
|
||||||
|
select="(ancestor::section |
|
||||||
|
ancestor::simplesect|
|
||||||
|
ancestor::sect1|
|
||||||
|
ancestor::sect2|
|
||||||
|
ancestor::sect3|
|
||||||
|
ancestor::sect4|
|
||||||
|
ancestor::sect5)[last()]"/>
|
||||||
|
|
||||||
|
<xsl:variable name="renderas">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$section/@renderas = 'sect1'">1</xsl:when>
|
||||||
|
<xsl:when test="$section/@renderas = 'sect2'">2</xsl:when>
|
||||||
|
<xsl:when test="$section/@renderas = 'sect3'">3</xsl:when>
|
||||||
|
<xsl:when test="$section/@renderas = 'sect4'">4</xsl:when>
|
||||||
|
<xsl:when test="$section/@renderas = 'sect5'">5</xsl:when>
|
||||||
|
<xsl:otherwise><xsl:value-of select="''"/></xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:variable name="level">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$renderas != ''">
|
||||||
|
<xsl:value-of select="$renderas"/>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:call-template name="section.level">
|
||||||
|
<xsl:with-param name="node" select="$section"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:call-template name="section.heading">
|
||||||
|
<xsl:with-param name="section" select="$section"/>
|
||||||
|
<xsl:with-param name="level" select="$level"/>
|
||||||
|
<xsl:with-param name="title">
|
||||||
|
<xsl:apply-templates select="$section" mode="object.title.markup">
|
||||||
|
<xsl:with-param name="allow-anchors" select="1"/>
|
||||||
|
</xsl:apply-templates>
|
||||||
|
<xsl:if test="$level > 0">
|
||||||
|
<xsl:call-template name="permalink">
|
||||||
|
<xsl:with-param name="node" select="$section"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
||||||
1259
bitbake/doc/template/titlepage.templates.xml
vendored
Normal file
1259
bitbake/doc/template/titlepage.templates.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
51
bitbake/doc/tools/docbook-to-pdf
Executable file
51
bitbake/doc/tools/docbook-to-pdf
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ -z "$1" -o -z "$2" ]; then
|
||||||
|
echo "usage: [-v] $0 <docbook file> <templatedir>"
|
||||||
|
echo
|
||||||
|
echo "*NOTE* you need xsltproc, fop and nwalsh docbook stylesheets"
|
||||||
|
echo " installed for this to work!"
|
||||||
|
echo
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
FO=`echo $1 | sed s/.xml/.fo/` || exit 1
|
||||||
|
PDF=`echo $1 | sed s/.xml/.pdf/` || exit 1
|
||||||
|
TEMPLATEDIR=$2
|
||||||
|
|
||||||
|
##
|
||||||
|
# These URI should be rewritten by your distribution's xml catalog to
|
||||||
|
# match your localy installed XSL stylesheets.
|
||||||
|
XSL_BASE_URI="http://docbook.sourceforge.net/release/xsl/current"
|
||||||
|
|
||||||
|
# Creates a temporary XSL stylesheet based on titlepage.xsl
|
||||||
|
xsltproc -o /tmp/titlepage.xsl \
|
||||||
|
--xinclude \
|
||||||
|
$XSL_BASE_URI/template/titlepage.xsl \
|
||||||
|
$TEMPLATEDIR/titlepage.templates.xml || exit 1
|
||||||
|
|
||||||
|
# Creates the file needed for FOP
|
||||||
|
xsltproc --xinclude \
|
||||||
|
--stringparam hyphenate false \
|
||||||
|
--stringparam formal.title.placement "figure after" \
|
||||||
|
--stringparam ulink.show 1 \
|
||||||
|
--stringparam body.font.master 9 \
|
||||||
|
--stringparam title.font.master 11 \
|
||||||
|
--stringparam draft.watermark.image "$TEMPLATEDIR/draft.png" \
|
||||||
|
--stringparam chapter.autolabel 1 \
|
||||||
|
--stringparam appendix.autolabel A \
|
||||||
|
--stringparam section.autolabel 1 \
|
||||||
|
--stringparam section.label.includes.component.label 1 \
|
||||||
|
--output $FO \
|
||||||
|
$TEMPLATEDIR/db-pdf.xsl \
|
||||||
|
$1 || exit 1
|
||||||
|
|
||||||
|
# Invokes the Java version of FOP. Uses the additional configuration file common/fop-config.xml
|
||||||
|
fop -c $TEMPLATEDIR/fop-config.xml -fo $FO -pdf $PDF || exit 1
|
||||||
|
|
||||||
|
rm -f $FO
|
||||||
|
rm -f /tmp/titlepage.xsl
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo " #### Success! $PDF ready. ####"
|
||||||
|
echo
|
||||||
@@ -1,18 +1,31 @@
|
|||||||
|
# ex:ts=4:sw=4:sts=4:et
|
||||||
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||||
#
|
#
|
||||||
# This is a copy on write dictionary and set which abuses classes to try and be nice and fast.
|
# This is a copy on write dictionary and set which abuses classes to try and be nice and fast.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006 Tim Ansell
|
# Copyright (C) 2006 Tim Ansell
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
#
|
#
|
||||||
# Please Note:
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
#Please Note:
|
||||||
# Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW.
|
# Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW.
|
||||||
# Assign a file to __warn__ to get warnings about slow operations.
|
# Assign a file to __warn__ to get warnings about slow operations.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import types
|
||||||
ImmutableTypes = (
|
ImmutableTypes = (
|
||||||
bool,
|
bool,
|
||||||
complex,
|
complex,
|
||||||
@@ -25,11 +38,9 @@ ImmutableTypes = (
|
|||||||
|
|
||||||
MUTABLE = "__mutable__"
|
MUTABLE = "__mutable__"
|
||||||
|
|
||||||
|
|
||||||
class COWMeta(type):
|
class COWMeta(type):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class COWDictMeta(COWMeta):
|
class COWDictMeta(COWMeta):
|
||||||
__warn__ = False
|
__warn__ = False
|
||||||
__hasmutable__ = False
|
__hasmutable__ = False
|
||||||
@@ -38,15 +49,12 @@ class COWDictMeta(COWMeta):
|
|||||||
def __str__(cls):
|
def __str__(cls):
|
||||||
# FIXME: I have magic numbers!
|
# FIXME: I have magic numbers!
|
||||||
return "<COWDict Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) - 3)
|
return "<COWDict Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) - 3)
|
||||||
|
|
||||||
__repr__ = __str__
|
__repr__ = __str__
|
||||||
|
|
||||||
def cow(cls):
|
def cow(cls):
|
||||||
class C(cls):
|
class C(cls):
|
||||||
__count__ = cls.__count__ + 1
|
__count__ = cls.__count__ + 1
|
||||||
|
|
||||||
return C
|
return C
|
||||||
|
|
||||||
copy = cow
|
copy = cow
|
||||||
__call__ = cow
|
__call__ = cow
|
||||||
|
|
||||||
@@ -78,9 +86,8 @@ class COWDictMeta(COWMeta):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
__getmarker__ = []
|
__getmarker__ = []
|
||||||
|
|
||||||
def __getreadonly__(cls, key, default=__getmarker__):
|
def __getreadonly__(cls, key, default=__getmarker__):
|
||||||
"""
|
"""\
|
||||||
Get a value (even if mutable) which you promise not to change.
|
Get a value (even if mutable) which you promise not to change.
|
||||||
"""
|
"""
|
||||||
return cls.__getitem__(key, default, True)
|
return cls.__getitem__(key, default, True)
|
||||||
@@ -147,29 +154,24 @@ class COWDictMeta(COWMeta):
|
|||||||
|
|
||||||
def iterkeys(cls):
|
def iterkeys(cls):
|
||||||
return cls.iter("keys")
|
return cls.iter("keys")
|
||||||
|
|
||||||
def itervalues(cls, readonly=False):
|
def itervalues(cls, readonly=False):
|
||||||
if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
|
if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
|
||||||
print("Warning: If you aren't going to change any of the values call with True.", file=cls.__warn__)
|
print("Warning: If you arn't going to change any of the values call with True.", file=cls.__warn__)
|
||||||
return cls.iter("values", readonly)
|
return cls.iter("values", readonly)
|
||||||
|
|
||||||
def iteritems(cls, readonly=False):
|
def iteritems(cls, readonly=False):
|
||||||
if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
|
if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
|
||||||
print("Warning: If you aren't going to change any of the values call with True.", file=cls.__warn__)
|
print("Warning: If you arn't going to change any of the values call with True.", file=cls.__warn__)
|
||||||
return cls.iter("items", readonly)
|
return cls.iter("items", readonly)
|
||||||
|
|
||||||
|
|
||||||
class COWSetMeta(COWDictMeta):
|
class COWSetMeta(COWDictMeta):
|
||||||
def __str__(cls):
|
def __str__(cls):
|
||||||
# FIXME: I have magic numbers!
|
# FIXME: I have magic numbers!
|
||||||
return "<COWSet Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) - 3)
|
return "<COWSet Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) -3)
|
||||||
|
|
||||||
__repr__ = __str__
|
__repr__ = __str__
|
||||||
|
|
||||||
def cow(cls):
|
def cow(cls):
|
||||||
class C(cls):
|
class C(cls):
|
||||||
__count__ = cls.__count__ + 1
|
__count__ = cls.__count__ + 1
|
||||||
|
|
||||||
return C
|
return C
|
||||||
|
|
||||||
def add(cls, value):
|
def add(cls, value):
|
||||||
@@ -187,11 +189,131 @@ class COWSetMeta(COWDictMeta):
|
|||||||
def iteritems(cls):
|
def iteritems(cls):
|
||||||
raise TypeError("sets don't have 'items'")
|
raise TypeError("sets don't have 'items'")
|
||||||
|
|
||||||
|
|
||||||
# These are the actual classes you use!
|
# These are the actual classes you use!
|
||||||
class COWDictBase(metaclass=COWDictMeta):
|
class COWDictBase(object, metaclass = COWDictMeta):
|
||||||
__count__ = 0
|
__count__ = 0
|
||||||
|
|
||||||
|
class COWSetBase(object, metaclass = COWSetMeta):
|
||||||
class COWSetBase(metaclass=COWSetMeta):
|
|
||||||
__count__ = 0
|
__count__ = 0
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
COWDictBase.__warn__ = sys.stderr
|
||||||
|
a = COWDictBase()
|
||||||
|
print("a", a)
|
||||||
|
|
||||||
|
a['a'] = 'a'
|
||||||
|
a['b'] = 'b'
|
||||||
|
a['dict'] = {}
|
||||||
|
|
||||||
|
b = a.copy()
|
||||||
|
print("b", b)
|
||||||
|
b['c'] = 'b'
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
print("a", a)
|
||||||
|
for x in a.iteritems():
|
||||||
|
print(x)
|
||||||
|
print("--")
|
||||||
|
print("b", b)
|
||||||
|
for x in b.iteritems():
|
||||||
|
print(x)
|
||||||
|
print()
|
||||||
|
|
||||||
|
b['dict']['a'] = 'b'
|
||||||
|
b['a'] = 'c'
|
||||||
|
|
||||||
|
print("a", a)
|
||||||
|
for x in a.iteritems():
|
||||||
|
print(x)
|
||||||
|
print("--")
|
||||||
|
print("b", b)
|
||||||
|
for x in b.iteritems():
|
||||||
|
print(x)
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
b['dict2']
|
||||||
|
except KeyError as e:
|
||||||
|
print("Okay!")
|
||||||
|
|
||||||
|
a['set'] = COWSetBase()
|
||||||
|
a['set'].add("o1")
|
||||||
|
a['set'].add("o1")
|
||||||
|
a['set'].add("o2")
|
||||||
|
|
||||||
|
print("a", a)
|
||||||
|
for x in a['set'].itervalues():
|
||||||
|
print(x)
|
||||||
|
print("--")
|
||||||
|
print("b", b)
|
||||||
|
for x in b['set'].itervalues():
|
||||||
|
print(x)
|
||||||
|
print()
|
||||||
|
|
||||||
|
b['set'].add('o3')
|
||||||
|
|
||||||
|
print("a", a)
|
||||||
|
for x in a['set'].itervalues():
|
||||||
|
print(x)
|
||||||
|
print("--")
|
||||||
|
print("b", b)
|
||||||
|
for x in b['set'].itervalues():
|
||||||
|
print(x)
|
||||||
|
print()
|
||||||
|
|
||||||
|
a['set2'] = set()
|
||||||
|
a['set2'].add("o1")
|
||||||
|
a['set2'].add("o1")
|
||||||
|
a['set2'].add("o2")
|
||||||
|
|
||||||
|
print("a", a)
|
||||||
|
for x in a.iteritems():
|
||||||
|
print(x)
|
||||||
|
print("--")
|
||||||
|
print("b", b)
|
||||||
|
for x in b.iteritems(readonly=True):
|
||||||
|
print(x)
|
||||||
|
print()
|
||||||
|
|
||||||
|
del b['b']
|
||||||
|
try:
|
||||||
|
print(b['b'])
|
||||||
|
except KeyError:
|
||||||
|
print("Yay! deleted key raises error")
|
||||||
|
|
||||||
|
if 'b' in b:
|
||||||
|
print("Boo!")
|
||||||
|
else:
|
||||||
|
print("Yay - has_key with delete works!")
|
||||||
|
|
||||||
|
print("a", a)
|
||||||
|
for x in a.iteritems():
|
||||||
|
print(x)
|
||||||
|
print("--")
|
||||||
|
print("b", b)
|
||||||
|
for x in b.iteritems(readonly=True):
|
||||||
|
print(x)
|
||||||
|
print()
|
||||||
|
|
||||||
|
b.__revertitem__('b')
|
||||||
|
|
||||||
|
print("a", a)
|
||||||
|
for x in a.iteritems():
|
||||||
|
print(x)
|
||||||
|
print("--")
|
||||||
|
print("b", b)
|
||||||
|
for x in b.iteritems(readonly=True):
|
||||||
|
print(x)
|
||||||
|
print()
|
||||||
|
|
||||||
|
b.__revertitem__('dict')
|
||||||
|
print("a", a)
|
||||||
|
for x in a.iteritems():
|
||||||
|
print(x)
|
||||||
|
print("--")
|
||||||
|
print("b", b)
|
||||||
|
for x in b.iteritems(readonly=True):
|
||||||
|
print(x)
|
||||||
|
print()
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# ex:ts=4:sw=4:sts=4:et
|
||||||
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||||
#
|
#
|
||||||
# BitBake Build System Python Library
|
# BitBake Build System Python Library
|
||||||
#
|
#
|
||||||
@@ -6,22 +8,25 @@
|
|||||||
#
|
#
|
||||||
# Based on Gentoo's portage.py.
|
# Based on Gentoo's portage.py.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
#
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
__version__ = "2.8.1"
|
__version__ = "1.42.0"
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info < (3, 8, 0):
|
if sys.version_info < (3, 4, 0):
|
||||||
raise RuntimeError("Sorry, python 3.8.0 or later is required for this version of bitbake")
|
raise RuntimeError("Sorry, python 3.4.0 or later is required for this version of bitbake")
|
||||||
|
|
||||||
if sys.version_info < (3, 10, 0):
|
|
||||||
# With python 3.8 and 3.9, we see errors of "libgcc_s.so.1 must be installed for pthread_cancel to work"
|
|
||||||
# https://stackoverflow.com/questions/64797838/libgcc-s-so-1-must-be-installed-for-pthread-cancel-to-work
|
|
||||||
# https://bugs.ams1.psf.io/issue42888
|
|
||||||
# so ensure libgcc_s is loaded early on
|
|
||||||
import ctypes
|
|
||||||
libgcc_s = ctypes.CDLL('libgcc_s.so.1')
|
|
||||||
|
|
||||||
class BBHandledException(Exception):
|
class BBHandledException(Exception):
|
||||||
"""
|
"""
|
||||||
@@ -36,71 +41,21 @@ class BBHandledException(Exception):
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
from collections import namedtuple
|
|
||||||
import multiprocessing as mp
|
|
||||||
|
|
||||||
# Python 3.14 changes the default multiprocessing context from "fork" to
|
|
||||||
# "forkserver". However, bitbake heavily relies on "fork" behavior to
|
|
||||||
# efficiently pass data to the child processes. Places that need this should do:
|
|
||||||
# from bb import multiprocessing
|
|
||||||
# in place of
|
|
||||||
# import multiprocessing
|
|
||||||
|
|
||||||
class MultiprocessingContext(object):
|
|
||||||
"""
|
|
||||||
Multiprocessing proxy object that uses the "fork" context for a property if
|
|
||||||
available, otherwise goes to the main multiprocessing module. This allows
|
|
||||||
it to be a drop-in replacement for the multiprocessing module, but use the
|
|
||||||
fork context
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
super().__setattr__("_ctx", mp.get_context("fork"))
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if hasattr(self._ctx, name):
|
|
||||||
return getattr(self._ctx, name)
|
|
||||||
return getattr(mp, name)
|
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
|
||||||
raise AttributeError(f"Unable to set attribute {name}")
|
|
||||||
|
|
||||||
multiprocessing = MultiprocessingContext()
|
|
||||||
|
|
||||||
|
|
||||||
class NullHandler(logging.Handler):
|
class NullHandler(logging.Handler):
|
||||||
def emit(self, record):
|
def emit(self, record):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class BBLoggerMixin(object):
|
Logger = logging.getLoggerClass()
|
||||||
def __init__(self, *args, **kwargs):
|
class BBLogger(Logger):
|
||||||
# Does nothing to allow calling super() from derived classes
|
def __init__(self, name):
|
||||||
pass
|
|
||||||
|
|
||||||
def setup_bblogger(self, name):
|
|
||||||
if name.split(".")[0] == "BitBake":
|
if name.split(".")[0] == "BitBake":
|
||||||
self.debug = self._debug_helper
|
self.debug = self.bbdebug
|
||||||
|
Logger.__init__(self, name)
|
||||||
def _debug_helper(self, *args, **kwargs):
|
|
||||||
return self.bbdebug(1, *args, **kwargs)
|
|
||||||
|
|
||||||
def debug2(self, *args, **kwargs):
|
|
||||||
return self.bbdebug(2, *args, **kwargs)
|
|
||||||
|
|
||||||
def debug3(self, *args, **kwargs):
|
|
||||||
return self.bbdebug(3, *args, **kwargs)
|
|
||||||
|
|
||||||
def bbdebug(self, level, msg, *args, **kwargs):
|
def bbdebug(self, level, msg, *args, **kwargs):
|
||||||
loglevel = logging.DEBUG - level + 1
|
return self.log(logging.DEBUG - level + 1, msg, *args, **kwargs)
|
||||||
if not bb.event.worker_pid:
|
|
||||||
if self.name in bb.msg.loggerDefaultDomains and loglevel > (bb.msg.loggerDefaultDomains[self.name]):
|
|
||||||
return
|
|
||||||
if loglevel < bb.msg.loggerDefaultLogLevel:
|
|
||||||
return
|
|
||||||
|
|
||||||
if not isinstance(level, int) or not isinstance(msg, str):
|
|
||||||
mainlogger.warning("Invalid arguments in bbdebug: %s" % repr((level, msg,) + args))
|
|
||||||
|
|
||||||
return self.log(loglevel, msg, *args, **kwargs)
|
|
||||||
|
|
||||||
def plain(self, msg, *args, **kwargs):
|
def plain(self, msg, *args, **kwargs):
|
||||||
return self.log(logging.INFO + 1, msg, *args, **kwargs)
|
return self.log(logging.INFO + 1, msg, *args, **kwargs)
|
||||||
@@ -111,63 +66,16 @@ class BBLoggerMixin(object):
|
|||||||
def verbnote(self, msg, *args, **kwargs):
|
def verbnote(self, msg, *args, **kwargs):
|
||||||
return self.log(logging.INFO + 2, msg, *args, **kwargs)
|
return self.log(logging.INFO + 2, msg, *args, **kwargs)
|
||||||
|
|
||||||
def warnonce(self, msg, *args, **kwargs):
|
|
||||||
return self.log(logging.WARNING - 1, msg, *args, **kwargs)
|
|
||||||
|
|
||||||
def erroronce(self, msg, *args, **kwargs):
|
|
||||||
return self.log(logging.ERROR - 1, msg, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
Logger = logging.getLoggerClass()
|
|
||||||
class BBLogger(Logger, BBLoggerMixin):
|
|
||||||
def __init__(self, name, *args, **kwargs):
|
|
||||||
self.setup_bblogger(name)
|
|
||||||
super().__init__(name, *args, **kwargs)
|
|
||||||
|
|
||||||
logging.raiseExceptions = False
|
logging.raiseExceptions = False
|
||||||
logging.setLoggerClass(BBLogger)
|
logging.setLoggerClass(BBLogger)
|
||||||
|
|
||||||
class BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin):
|
|
||||||
def __init__(self, logger, *args, **kwargs):
|
|
||||||
self.setup_bblogger(logger.name)
|
|
||||||
super().__init__(logger, *args, **kwargs)
|
|
||||||
|
|
||||||
if sys.version_info < (3, 6):
|
|
||||||
# These properties were added in Python 3.6. Add them in older versions
|
|
||||||
# for compatibility
|
|
||||||
@property
|
|
||||||
def manager(self):
|
|
||||||
return self.logger.manager
|
|
||||||
|
|
||||||
@manager.setter
|
|
||||||
def manager(self, value):
|
|
||||||
self.logger.manager = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return self.logger.name
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
logger = self.logger
|
|
||||||
level = logger.getLevelName(logger.getEffectiveLevel())
|
|
||||||
return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level)
|
|
||||||
|
|
||||||
logging.LoggerAdapter = BBLoggerAdapter
|
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake")
|
logger = logging.getLogger("BitBake")
|
||||||
logger.addHandler(NullHandler())
|
logger.addHandler(NullHandler())
|
||||||
logger.setLevel(logging.DEBUG - 2)
|
logger.setLevel(logging.DEBUG - 2)
|
||||||
|
|
||||||
mainlogger = logging.getLogger("BitBake.Main")
|
mainlogger = logging.getLogger("BitBake.Main")
|
||||||
|
|
||||||
class PrefixLoggerAdapter(logging.LoggerAdapter):
|
|
||||||
def __init__(self, prefix, logger):
|
|
||||||
super().__init__(logger, {})
|
|
||||||
self.__msg_prefix = prefix
|
|
||||||
|
|
||||||
def process(self, msg, kwargs):
|
|
||||||
return "%s%s" %(self.__msg_prefix, msg), kwargs
|
|
||||||
|
|
||||||
# This has to be imported after the setLoggerClass, as the import of bb.msg
|
# This has to be imported after the setLoggerClass, as the import of bb.msg
|
||||||
# can result in construction of the various loggers.
|
# can result in construction of the various loggers.
|
||||||
import bb.msg
|
import bb.msg
|
||||||
@@ -184,7 +92,7 @@ def debug(lvl, *args):
|
|||||||
mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
|
mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
|
||||||
args = (lvl,) + args
|
args = (lvl,) + args
|
||||||
lvl = 1
|
lvl = 1
|
||||||
mainlogger.bbdebug(lvl, ''.join(args))
|
mainlogger.debug(lvl, ''.join(args))
|
||||||
|
|
||||||
def note(*args):
|
def note(*args):
|
||||||
mainlogger.info(''.join(args))
|
mainlogger.info(''.join(args))
|
||||||
@@ -204,15 +112,9 @@ def verbnote(*args):
|
|||||||
def warn(*args):
|
def warn(*args):
|
||||||
mainlogger.warning(''.join(args))
|
mainlogger.warning(''.join(args))
|
||||||
|
|
||||||
def warnonce(*args):
|
|
||||||
mainlogger.warnonce(''.join(args))
|
|
||||||
|
|
||||||
def error(*args, **kwargs):
|
def error(*args, **kwargs):
|
||||||
mainlogger.error(''.join(args), extra=kwargs)
|
mainlogger.error(''.join(args), extra=kwargs)
|
||||||
|
|
||||||
def erroronce(*args):
|
|
||||||
mainlogger.erroronce(''.join(args))
|
|
||||||
|
|
||||||
def fatal(*args, **kwargs):
|
def fatal(*args, **kwargs):
|
||||||
mainlogger.critical(''.join(args), extra=kwargs)
|
mainlogger.critical(''.join(args), extra=kwargs)
|
||||||
raise BBHandledException()
|
raise BBHandledException()
|
||||||
@@ -256,14 +158,3 @@ def deprecate_import(current, modulename, fromlist, renames = None):
|
|||||||
|
|
||||||
setattr(sys.modules[current], newname, newobj)
|
setattr(sys.modules[current], newname, newobj)
|
||||||
|
|
||||||
TaskData = namedtuple("TaskData", [
|
|
||||||
"pn",
|
|
||||||
"taskname",
|
|
||||||
"fn",
|
|
||||||
"deps",
|
|
||||||
"provides",
|
|
||||||
"taskhash",
|
|
||||||
"unihash",
|
|
||||||
"hashfn",
|
|
||||||
"taskhash_deps",
|
|
||||||
])
|
|
||||||
|
|||||||
@@ -1,215 +0,0 @@
|
|||||||
#! /usr/bin/env python3
|
|
||||||
#
|
|
||||||
# Copyright 2023 by Garmin Ltd. or its subsidiaries
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import ctypes
|
|
||||||
import os
|
|
||||||
import errno
|
|
||||||
import pwd
|
|
||||||
import grp
|
|
||||||
|
|
||||||
libacl = ctypes.CDLL("libacl.so.1", use_errno=True)
|
|
||||||
|
|
||||||
|
|
||||||
ACL_TYPE_ACCESS = 0x8000
|
|
||||||
ACL_TYPE_DEFAULT = 0x4000
|
|
||||||
|
|
||||||
ACL_FIRST_ENTRY = 0
|
|
||||||
ACL_NEXT_ENTRY = 1
|
|
||||||
|
|
||||||
ACL_UNDEFINED_TAG = 0x00
|
|
||||||
ACL_USER_OBJ = 0x01
|
|
||||||
ACL_USER = 0x02
|
|
||||||
ACL_GROUP_OBJ = 0x04
|
|
||||||
ACL_GROUP = 0x08
|
|
||||||
ACL_MASK = 0x10
|
|
||||||
ACL_OTHER = 0x20
|
|
||||||
|
|
||||||
ACL_READ = 0x04
|
|
||||||
ACL_WRITE = 0x02
|
|
||||||
ACL_EXECUTE = 0x01
|
|
||||||
|
|
||||||
acl_t = ctypes.c_void_p
|
|
||||||
acl_entry_t = ctypes.c_void_p
|
|
||||||
acl_permset_t = ctypes.c_void_p
|
|
||||||
acl_perm_t = ctypes.c_uint
|
|
||||||
|
|
||||||
acl_tag_t = ctypes.c_int
|
|
||||||
|
|
||||||
libacl.acl_free.argtypes = [acl_t]
|
|
||||||
|
|
||||||
|
|
||||||
def acl_free(acl):
|
|
||||||
libacl.acl_free(acl)
|
|
||||||
|
|
||||||
|
|
||||||
libacl.acl_get_file.restype = acl_t
|
|
||||||
libacl.acl_get_file.argtypes = [ctypes.c_char_p, ctypes.c_uint]
|
|
||||||
|
|
||||||
|
|
||||||
def acl_get_file(path, typ):
|
|
||||||
acl = libacl.acl_get_file(os.fsencode(path), typ)
|
|
||||||
if acl is None:
|
|
||||||
err = ctypes.get_errno()
|
|
||||||
raise OSError(err, os.strerror(err), str(path))
|
|
||||||
|
|
||||||
return acl
|
|
||||||
|
|
||||||
|
|
||||||
libacl.acl_get_entry.argtypes = [acl_t, ctypes.c_int, ctypes.c_void_p]
|
|
||||||
|
|
||||||
|
|
||||||
def acl_get_entry(acl, entry_id):
|
|
||||||
entry = acl_entry_t()
|
|
||||||
ret = libacl.acl_get_entry(acl, entry_id, ctypes.byref(entry))
|
|
||||||
if ret < 0:
|
|
||||||
err = ctypes.get_errno()
|
|
||||||
raise OSError(err, os.strerror(err))
|
|
||||||
|
|
||||||
if ret == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return entry
|
|
||||||
|
|
||||||
|
|
||||||
libacl.acl_get_tag_type.argtypes = [acl_entry_t, ctypes.c_void_p]
|
|
||||||
|
|
||||||
|
|
||||||
def acl_get_tag_type(entry_d):
|
|
||||||
tag = acl_tag_t()
|
|
||||||
ret = libacl.acl_get_tag_type(entry_d, ctypes.byref(tag))
|
|
||||||
if ret < 0:
|
|
||||||
err = ctypes.get_errno()
|
|
||||||
raise OSError(err, os.strerror(err))
|
|
||||||
return tag.value
|
|
||||||
|
|
||||||
|
|
||||||
libacl.acl_get_qualifier.restype = ctypes.c_void_p
|
|
||||||
libacl.acl_get_qualifier.argtypes = [acl_entry_t]
|
|
||||||
|
|
||||||
|
|
||||||
def acl_get_qualifier(entry_d):
|
|
||||||
ret = libacl.acl_get_qualifier(entry_d)
|
|
||||||
if ret is None:
|
|
||||||
err = ctypes.get_errno()
|
|
||||||
raise OSError(err, os.strerror(err))
|
|
||||||
return ctypes.c_void_p(ret)
|
|
||||||
|
|
||||||
|
|
||||||
libacl.acl_get_permset.argtypes = [acl_entry_t, ctypes.c_void_p]
|
|
||||||
|
|
||||||
|
|
||||||
def acl_get_permset(entry_d):
|
|
||||||
permset = acl_permset_t()
|
|
||||||
ret = libacl.acl_get_permset(entry_d, ctypes.byref(permset))
|
|
||||||
if ret < 0:
|
|
||||||
err = ctypes.get_errno()
|
|
||||||
raise OSError(err, os.strerror(err))
|
|
||||||
|
|
||||||
return permset
|
|
||||||
|
|
||||||
|
|
||||||
libacl.acl_get_perm.argtypes = [acl_permset_t, acl_perm_t]
|
|
||||||
|
|
||||||
|
|
||||||
def acl_get_perm(permset_d, perm):
|
|
||||||
ret = libacl.acl_get_perm(permset_d, perm)
|
|
||||||
if ret < 0:
|
|
||||||
err = ctypes.get_errno()
|
|
||||||
raise OSError(err, os.strerror(err))
|
|
||||||
return bool(ret)
|
|
||||||
|
|
||||||
|
|
||||||
class Entry(object):
|
|
||||||
def __init__(self, tag, qualifier, mode):
|
|
||||||
self.tag = tag
|
|
||||||
self.qualifier = qualifier
|
|
||||||
self.mode = mode
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
typ = ""
|
|
||||||
qual = ""
|
|
||||||
if self.tag == ACL_USER:
|
|
||||||
typ = "user"
|
|
||||||
qual = pwd.getpwuid(self.qualifier).pw_name
|
|
||||||
elif self.tag == ACL_GROUP:
|
|
||||||
typ = "group"
|
|
||||||
qual = grp.getgrgid(self.qualifier).gr_name
|
|
||||||
elif self.tag == ACL_USER_OBJ:
|
|
||||||
typ = "user"
|
|
||||||
elif self.tag == ACL_GROUP_OBJ:
|
|
||||||
typ = "group"
|
|
||||||
elif self.tag == ACL_MASK:
|
|
||||||
typ = "mask"
|
|
||||||
elif self.tag == ACL_OTHER:
|
|
||||||
typ = "other"
|
|
||||||
|
|
||||||
r = "r" if self.mode & ACL_READ else "-"
|
|
||||||
w = "w" if self.mode & ACL_WRITE else "-"
|
|
||||||
x = "x" if self.mode & ACL_EXECUTE else "-"
|
|
||||||
|
|
||||||
return f"{typ}:{qual}:{r}{w}{x}"
|
|
||||||
|
|
||||||
|
|
||||||
class ACL(object):
|
|
||||||
def __init__(self, acl):
|
|
||||||
self.acl = acl
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
acl_free(self.acl)
|
|
||||||
|
|
||||||
def entries(self):
|
|
||||||
entry_id = ACL_FIRST_ENTRY
|
|
||||||
while True:
|
|
||||||
entry = acl_get_entry(self.acl, entry_id)
|
|
||||||
if entry is None:
|
|
||||||
break
|
|
||||||
|
|
||||||
permset = acl_get_permset(entry)
|
|
||||||
|
|
||||||
mode = 0
|
|
||||||
for m in (ACL_READ, ACL_WRITE, ACL_EXECUTE):
|
|
||||||
if acl_get_perm(permset, m):
|
|
||||||
mode |= m
|
|
||||||
|
|
||||||
qualifier = None
|
|
||||||
tag = acl_get_tag_type(entry)
|
|
||||||
|
|
||||||
if tag == ACL_USER or tag == ACL_GROUP:
|
|
||||||
qual = acl_get_qualifier(entry)
|
|
||||||
qualifier = ctypes.cast(qual, ctypes.POINTER(ctypes.c_int))[0]
|
|
||||||
|
|
||||||
yield Entry(tag, qualifier, mode)
|
|
||||||
|
|
||||||
entry_id = ACL_NEXT_ENTRY
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_path(cls, path, typ):
|
|
||||||
acl = acl_get_file(path, typ)
|
|
||||||
return cls(acl)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
import argparse
|
|
||||||
import pwd
|
|
||||||
import grp
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("path", help="File Path", type=Path)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
acl = ACL.from_path(args.path, ACL_TYPE_ACCESS)
|
|
||||||
for entry in acl.entries():
|
|
||||||
print(str(entry))
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright BitBake Contributors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
from .client import AsyncClient, Client, ClientPool
|
|
||||||
from .serv import AsyncServer, AsyncServerConnection
|
|
||||||
from .connection import DEFAULT_MAX_CHUNK
|
|
||||||
from .exceptions import (
|
|
||||||
ClientError,
|
|
||||||
ServerError,
|
|
||||||
ConnectionClosedError,
|
|
||||||
InvokeError,
|
|
||||||
)
|
|
||||||
@@ -1,317 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright BitBake Contributors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
import abc
|
|
||||||
import asyncio
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
import contextlib
|
|
||||||
from threading import Thread
|
|
||||||
from .connection import StreamConnection, WebsocketConnection, DEFAULT_MAX_CHUNK
|
|
||||||
from .exceptions import ConnectionClosedError, InvokeError
|
|
||||||
|
|
||||||
UNIX_PREFIX = "unix://"
|
|
||||||
WS_PREFIX = "ws://"
|
|
||||||
WSS_PREFIX = "wss://"
|
|
||||||
|
|
||||||
ADDR_TYPE_UNIX = 0
|
|
||||||
ADDR_TYPE_TCP = 1
|
|
||||||
ADDR_TYPE_WS = 2
|
|
||||||
|
|
||||||
def parse_address(addr):
|
|
||||||
if addr.startswith(UNIX_PREFIX):
|
|
||||||
return (ADDR_TYPE_UNIX, (addr[len(UNIX_PREFIX) :],))
|
|
||||||
elif addr.startswith(WS_PREFIX) or addr.startswith(WSS_PREFIX):
|
|
||||||
return (ADDR_TYPE_WS, (addr,))
|
|
||||||
else:
|
|
||||||
m = re.match(r"\[(?P<host>[^\]]*)\]:(?P<port>\d+)$", addr)
|
|
||||||
if m is not None:
|
|
||||||
host = m.group("host")
|
|
||||||
port = m.group("port")
|
|
||||||
else:
|
|
||||||
host, port = addr.split(":")
|
|
||||||
|
|
||||||
return (ADDR_TYPE_TCP, (host, int(port)))
|
|
||||||
|
|
||||||
class AsyncClient(object):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
proto_name,
|
|
||||||
proto_version,
|
|
||||||
logger,
|
|
||||||
timeout=30,
|
|
||||||
server_headers=False,
|
|
||||||
headers={},
|
|
||||||
):
|
|
||||||
self.socket = None
|
|
||||||
self.max_chunk = DEFAULT_MAX_CHUNK
|
|
||||||
self.proto_name = proto_name
|
|
||||||
self.proto_version = proto_version
|
|
||||||
self.logger = logger
|
|
||||||
self.timeout = timeout
|
|
||||||
self.needs_server_headers = server_headers
|
|
||||||
self.server_headers = {}
|
|
||||||
self.headers = headers
|
|
||||||
|
|
||||||
async def connect_tcp(self, address, port):
|
|
||||||
async def connect_sock():
|
|
||||||
reader, writer = await asyncio.open_connection(address, port)
|
|
||||||
return StreamConnection(reader, writer, self.timeout, self.max_chunk)
|
|
||||||
|
|
||||||
self._connect_sock = connect_sock
|
|
||||||
|
|
||||||
async def connect_unix(self, path):
|
|
||||||
async def connect_sock():
|
|
||||||
# AF_UNIX has path length issues so chdir here to workaround
|
|
||||||
cwd = os.getcwd()
|
|
||||||
try:
|
|
||||||
os.chdir(os.path.dirname(path))
|
|
||||||
# The socket must be opened synchronously so that CWD doesn't get
|
|
||||||
# changed out from underneath us so we pass as a sock into asyncio
|
|
||||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
|
|
||||||
sock.connect(os.path.basename(path))
|
|
||||||
finally:
|
|
||||||
os.chdir(cwd)
|
|
||||||
reader, writer = await asyncio.open_unix_connection(sock=sock)
|
|
||||||
return StreamConnection(reader, writer, self.timeout, self.max_chunk)
|
|
||||||
|
|
||||||
self._connect_sock = connect_sock
|
|
||||||
|
|
||||||
async def connect_websocket(self, uri):
|
|
||||||
import websockets
|
|
||||||
|
|
||||||
async def connect_sock():
|
|
||||||
websocket = await websockets.connect(
|
|
||||||
uri,
|
|
||||||
ping_interval=None,
|
|
||||||
open_timeout=self.timeout,
|
|
||||||
)
|
|
||||||
return WebsocketConnection(websocket, self.timeout)
|
|
||||||
|
|
||||||
self._connect_sock = connect_sock
|
|
||||||
|
|
||||||
async def setup_connection(self):
|
|
||||||
# Send headers
|
|
||||||
await self.socket.send("%s %s" % (self.proto_name, self.proto_version))
|
|
||||||
await self.socket.send(
|
|
||||||
"needs-headers: %s" % ("true" if self.needs_server_headers else "false")
|
|
||||||
)
|
|
||||||
for k, v in self.headers.items():
|
|
||||||
await self.socket.send("%s: %s" % (k, v))
|
|
||||||
|
|
||||||
# End of headers
|
|
||||||
await self.socket.send("")
|
|
||||||
|
|
||||||
self.server_headers = {}
|
|
||||||
if self.needs_server_headers:
|
|
||||||
while True:
|
|
||||||
line = await self.socket.recv()
|
|
||||||
if not line:
|
|
||||||
# End headers
|
|
||||||
break
|
|
||||||
tag, value = line.split(":", 1)
|
|
||||||
self.server_headers[tag.lower()] = value.strip()
|
|
||||||
|
|
||||||
async def get_header(self, tag, default):
|
|
||||||
await self.connect()
|
|
||||||
return self.server_headers.get(tag, default)
|
|
||||||
|
|
||||||
async def connect(self):
|
|
||||||
if self.socket is None:
|
|
||||||
self.socket = await self._connect_sock()
|
|
||||||
await self.setup_connection()
|
|
||||||
|
|
||||||
async def disconnect(self):
|
|
||||||
if self.socket is not None:
|
|
||||||
await self.socket.close()
|
|
||||||
self.socket = None
|
|
||||||
|
|
||||||
async def close(self):
|
|
||||||
await self.disconnect()
|
|
||||||
|
|
||||||
async def _send_wrapper(self, proc):
|
|
||||||
count = 0
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
await self.connect()
|
|
||||||
return await proc()
|
|
||||||
except (
|
|
||||||
OSError,
|
|
||||||
ConnectionError,
|
|
||||||
ConnectionClosedError,
|
|
||||||
json.JSONDecodeError,
|
|
||||||
UnicodeDecodeError,
|
|
||||||
) as e:
|
|
||||||
self.logger.warning("Error talking to server: %s" % e)
|
|
||||||
if count >= 3:
|
|
||||||
if not isinstance(e, ConnectionError):
|
|
||||||
raise ConnectionError(str(e))
|
|
||||||
raise e
|
|
||||||
await self.close()
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
def check_invoke_error(self, msg):
|
|
||||||
if isinstance(msg, dict) and "invoke-error" in msg:
|
|
||||||
raise InvokeError(msg["invoke-error"]["message"])
|
|
||||||
|
|
||||||
async def invoke(self, msg):
|
|
||||||
async def proc():
|
|
||||||
await self.socket.send_message(msg)
|
|
||||||
return await self.socket.recv_message()
|
|
||||||
|
|
||||||
result = await self._send_wrapper(proc)
|
|
||||||
self.check_invoke_error(result)
|
|
||||||
return result
|
|
||||||
|
|
||||||
async def ping(self):
|
|
||||||
return await self.invoke({"ping": {}})
|
|
||||||
|
|
||||||
async def __aenter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
async def __aexit__(self, exc_type, exc_value, traceback):
|
|
||||||
await self.close()
|
|
||||||
|
|
||||||
|
|
||||||
class Client(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.client = self._get_async_client()
|
|
||||||
self.loop = asyncio.new_event_loop()
|
|
||||||
|
|
||||||
# Override any pre-existing loop.
|
|
||||||
# Without this, the PR server export selftest triggers a hang
|
|
||||||
# when running with Python 3.7. The drawback is that there is
|
|
||||||
# potential for issues if the PR and hash equiv (or some new)
|
|
||||||
# clients need to both be instantiated in the same process.
|
|
||||||
# This should be revisited if/when Python 3.9 becomes the
|
|
||||||
# minimum required version for BitBake, as it seems not
|
|
||||||
# required (but harmless) with it.
|
|
||||||
asyncio.set_event_loop(self.loop)
|
|
||||||
|
|
||||||
self._add_methods("connect_tcp", "ping")
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def _get_async_client(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _get_downcall_wrapper(self, downcall):
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
return self.loop.run_until_complete(downcall(*args, **kwargs))
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
def _add_methods(self, *methods):
|
|
||||||
for m in methods:
|
|
||||||
downcall = getattr(self.client, m)
|
|
||||||
setattr(self, m, self._get_downcall_wrapper(downcall))
|
|
||||||
|
|
||||||
def connect_unix(self, path):
|
|
||||||
self.loop.run_until_complete(self.client.connect_unix(path))
|
|
||||||
self.loop.run_until_complete(self.client.connect())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def max_chunk(self):
|
|
||||||
return self.client.max_chunk
|
|
||||||
|
|
||||||
@max_chunk.setter
|
|
||||||
def max_chunk(self, value):
|
|
||||||
self.client.max_chunk = value
|
|
||||||
|
|
||||||
def disconnect(self):
|
|
||||||
self.loop.run_until_complete(self.client.close())
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
if self.loop:
|
|
||||||
self.loop.run_until_complete(self.client.close())
|
|
||||||
if sys.version_info >= (3, 6):
|
|
||||||
self.loop.run_until_complete(self.loop.shutdown_asyncgens())
|
|
||||||
self.loop.close()
|
|
||||||
self.loop = None
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
|
||||||
self.close()
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class ClientPool(object):
|
|
||||||
def __init__(self, max_clients):
|
|
||||||
self.avail_clients = []
|
|
||||||
self.num_clients = 0
|
|
||||||
self.max_clients = max_clients
|
|
||||||
self.loop = None
|
|
||||||
self.client_condition = None
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
async def _new_client(self):
|
|
||||||
raise NotImplementedError("Must be implemented in derived class")
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
if self.client_condition:
|
|
||||||
self.client_condition = None
|
|
||||||
|
|
||||||
if self.loop:
|
|
||||||
self.loop.run_until_complete(self.__close_clients())
|
|
||||||
self.loop.run_until_complete(self.loop.shutdown_asyncgens())
|
|
||||||
self.loop.close()
|
|
||||||
self.loop = None
|
|
||||||
|
|
||||||
def run_tasks(self, tasks):
|
|
||||||
if not self.loop:
|
|
||||||
self.loop = asyncio.new_event_loop()
|
|
||||||
|
|
||||||
thread = Thread(target=self.__thread_main, args=(tasks,))
|
|
||||||
thread.start()
|
|
||||||
thread.join()
|
|
||||||
|
|
||||||
@contextlib.asynccontextmanager
|
|
||||||
async def get_client(self):
|
|
||||||
async with self.client_condition:
|
|
||||||
if self.avail_clients:
|
|
||||||
client = self.avail_clients.pop()
|
|
||||||
elif self.num_clients < self.max_clients:
|
|
||||||
self.num_clients += 1
|
|
||||||
client = await self._new_client()
|
|
||||||
else:
|
|
||||||
while not self.avail_clients:
|
|
||||||
await self.client_condition.wait()
|
|
||||||
client = self.avail_clients.pop()
|
|
||||||
|
|
||||||
try:
|
|
||||||
yield client
|
|
||||||
finally:
|
|
||||||
async with self.client_condition:
|
|
||||||
self.avail_clients.append(client)
|
|
||||||
self.client_condition.notify()
|
|
||||||
|
|
||||||
def __thread_main(self, tasks):
|
|
||||||
async def process_task(task):
|
|
||||||
async with self.get_client() as client:
|
|
||||||
await task(client)
|
|
||||||
|
|
||||||
asyncio.set_event_loop(self.loop)
|
|
||||||
if not self.client_condition:
|
|
||||||
self.client_condition = asyncio.Condition()
|
|
||||||
tasks = [process_task(t) for t in tasks]
|
|
||||||
self.loop.run_until_complete(asyncio.gather(*tasks))
|
|
||||||
|
|
||||||
async def __close_clients(self):
|
|
||||||
for c in self.avail_clients:
|
|
||||||
await c.close()
|
|
||||||
self.avail_clients = []
|
|
||||||
self.num_clients = 0
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
|
||||||
self.close()
|
|
||||||
return False
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright BitBake Contributors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import itertools
|
|
||||||
import json
|
|
||||||
from datetime import datetime
|
|
||||||
from .exceptions import ClientError, ConnectionClosedError
|
|
||||||
|
|
||||||
|
|
||||||
# The Python async server defaults to a 64K receive buffer, so we hardcode our
|
|
||||||
# maximum chunk size. It would be better if the client and server reported to
|
|
||||||
# each other what the maximum chunk sizes were, but that will slow down the
|
|
||||||
# connection setup with a round trip delay so I'd rather not do that unless it
|
|
||||||
# is necessary
|
|
||||||
DEFAULT_MAX_CHUNK = 32 * 1024
|
|
||||||
|
|
||||||
|
|
||||||
def chunkify(msg, max_chunk):
|
|
||||||
if len(msg) < max_chunk - 1:
|
|
||||||
yield "".join((msg, "\n"))
|
|
||||||
else:
|
|
||||||
yield "".join((json.dumps({"chunk-stream": None}), "\n"))
|
|
||||||
|
|
||||||
args = [iter(msg)] * (max_chunk - 1)
|
|
||||||
for m in map("".join, itertools.zip_longest(*args, fillvalue="")):
|
|
||||||
yield "".join(itertools.chain(m, "\n"))
|
|
||||||
yield "\n"
|
|
||||||
|
|
||||||
|
|
||||||
def json_serialize(obj):
|
|
||||||
if isinstance(obj, datetime):
|
|
||||||
return obj.isoformat()
|
|
||||||
raise TypeError("Type %s not serializeable" % type(obj))
|
|
||||||
|
|
||||||
|
|
||||||
class StreamConnection(object):
|
|
||||||
def __init__(self, reader, writer, timeout, max_chunk=DEFAULT_MAX_CHUNK):
|
|
||||||
self.reader = reader
|
|
||||||
self.writer = writer
|
|
||||||
self.timeout = timeout
|
|
||||||
self.max_chunk = max_chunk
|
|
||||||
|
|
||||||
@property
|
|
||||||
def address(self):
|
|
||||||
return self.writer.get_extra_info("peername")
|
|
||||||
|
|
||||||
async def send_message(self, msg):
|
|
||||||
for c in chunkify(json.dumps(msg, default=json_serialize), self.max_chunk):
|
|
||||||
self.writer.write(c.encode("utf-8"))
|
|
||||||
await self.writer.drain()
|
|
||||||
|
|
||||||
async def recv_message(self):
|
|
||||||
l = await self.recv()
|
|
||||||
|
|
||||||
m = json.loads(l)
|
|
||||||
if not m:
|
|
||||||
return m
|
|
||||||
|
|
||||||
if "chunk-stream" in m:
|
|
||||||
lines = []
|
|
||||||
while True:
|
|
||||||
l = await self.recv()
|
|
||||||
if not l:
|
|
||||||
break
|
|
||||||
lines.append(l)
|
|
||||||
|
|
||||||
m = json.loads("".join(lines))
|
|
||||||
|
|
||||||
return m
|
|
||||||
|
|
||||||
async def send(self, msg):
|
|
||||||
self.writer.write(("%s\n" % msg).encode("utf-8"))
|
|
||||||
await self.writer.drain()
|
|
||||||
|
|
||||||
async def recv(self):
|
|
||||||
if self.timeout < 0:
|
|
||||||
line = await self.reader.readline()
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
line = await asyncio.wait_for(self.reader.readline(), self.timeout)
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
raise ConnectionError("Timed out waiting for data")
|
|
||||||
|
|
||||||
if not line:
|
|
||||||
raise ConnectionClosedError("Connection closed")
|
|
||||||
|
|
||||||
line = line.decode("utf-8")
|
|
||||||
|
|
||||||
if not line.endswith("\n"):
|
|
||||||
raise ConnectionError("Bad message %r" % (line))
|
|
||||||
|
|
||||||
return line.rstrip()
|
|
||||||
|
|
||||||
async def close(self):
|
|
||||||
self.reader = None
|
|
||||||
if self.writer is not None:
|
|
||||||
self.writer.close()
|
|
||||||
self.writer = None
|
|
||||||
|
|
||||||
|
|
||||||
class WebsocketConnection(object):
|
|
||||||
def __init__(self, socket, timeout):
|
|
||||||
self.socket = socket
|
|
||||||
self.timeout = timeout
|
|
||||||
|
|
||||||
@property
|
|
||||||
def address(self):
|
|
||||||
return ":".join(str(s) for s in self.socket.remote_address)
|
|
||||||
|
|
||||||
async def send_message(self, msg):
|
|
||||||
await self.send(json.dumps(msg, default=json_serialize))
|
|
||||||
|
|
||||||
async def recv_message(self):
|
|
||||||
m = await self.recv()
|
|
||||||
return json.loads(m)
|
|
||||||
|
|
||||||
async def send(self, msg):
|
|
||||||
import websockets.exceptions
|
|
||||||
|
|
||||||
try:
|
|
||||||
await self.socket.send(msg)
|
|
||||||
except websockets.exceptions.ConnectionClosed:
|
|
||||||
raise ConnectionClosedError("Connection closed")
|
|
||||||
|
|
||||||
async def recv(self):
|
|
||||||
import websockets.exceptions
|
|
||||||
|
|
||||||
try:
|
|
||||||
if self.timeout < 0:
|
|
||||||
return await self.socket.recv()
|
|
||||||
|
|
||||||
try:
|
|
||||||
return await asyncio.wait_for(self.socket.recv(), self.timeout)
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
raise ConnectionError("Timed out waiting for data")
|
|
||||||
except websockets.exceptions.ConnectionClosed:
|
|
||||||
raise ConnectionClosedError("Connection closed")
|
|
||||||
|
|
||||||
async def close(self):
|
|
||||||
if self.socket is not None:
|
|
||||||
await self.socket.close()
|
|
||||||
self.socket = None
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright BitBake Contributors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
class ClientError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class InvokeError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ServerError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionClosedError(Exception):
|
|
||||||
pass
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user