📄 package.contents.html
字号:
be repeated, to ensure that all option consequences take effect. Care
is taken that this will not result in unnecessary rebuilds.</P
><DIV
CLASS="NOTE"
><BLOCKQUOTE
CLASS="NOTE"
><P
><B
>Note: </B
>At present this step needs to be invoked manually. In a future version
the generated makefile may if desired perform this step automatically,
using a dependency on the <TT
CLASS="FILENAME"
>ecos.ecc</TT
> savefile.</P
></BLOCKQUOTE
></DIV
></LI
><LI
><P
>The first step in an actual build is to make sure that the install
tree contains all exported header files. All compilations will use
the install tree's <TT
CLASS="FILENAME"
>include</TT
>
directory as one of the places to search for header files.</P
></LI
><LI
><P
>All source files relevant to the current configuration get compiled.
This involves a set of compiler flags initialized on a per-target
basis, with each package being able to modify these flags, and with
the ability for the user to override the flags as well. Care has to be
taken here to avoid inappropriate target-dependencies in packages that
are intended to be portable. The component framework has built-in
knowledge of how to handle C, C++ and assembler source files —
other languages may be added in future, as and when necessary. The
<A
HREF="ref.compile.html"
><SPAN
CLASS="PROPERTY"
>compile</SPAN
></A
> property is used to
list the files that should get compiled. All object files end up in
the build tree.</P
></LI
><LI
><P
>Once all the object files have been built they are collected into a
library, typically <TT
CLASS="FILENAME"
>libtarget.a</TT
>, which can then be
linked with application code. The library is generated in the install
tree. </P
></LI
><LI
><P
>The component framework provides support for custom build steps, using
the <A
HREF="ref.make-object.html"
><SPAN
CLASS="PROPERTY"
>make_object</SPAN
></A
> and
<A
HREF="ref.make.html"
><SPAN
CLASS="PROPERTY"
>make</SPAN
></A
> properties. The results of
these custom build steps can either be object files that should end up
in a library, or other files such as a linker script. It is possible
to control the order in which these custom build steps take place, for
example it is possible to run a particular build step before any of
the compilations happen.</P
></LI
></OL
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="PACKAGE.SOURCE">Configurable Source Code</H2
><P
>All packages should be totally portable to all target hardware (with
the obvious exceptions of HAL and device driver packages). They should
also be totally bug-free, require the absolute minimum amount of code
and data space, be so efficient that cpu time usage is negligible, and
provide lots of configuration options so that application developers
have full control over the behavior. The configuration options are
optional only if a package can meet the requirements of every
potential application without any overheads. It is not the purpose of
this guide to explain how to achieve all of these requirements.</P
><P
>The <SPAN
CLASS="APPLICATION"
>eCos</SPAN
> component framework does have some important implications
for the source code: compiler flag dependencies; package interfaces
vs. implementations; and how configuration options affect source code.</P
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="PACKAGE.SOURCE.FLAGS">Compiler Flag Dependencies</H3
><P
>Wherever possible component writers should avoid dependencies on
particular compiler flags. Any such dependencies are likely to impact
portability. For example, if one package needs to be built in
big-endian mode and another package needs to be built in little-endian
mode then usually it will not be possible for application developers
to use both packages at the same time; in addition the application
developer is no longer given a choice in the matter. It is far better
for the package source code to adapt the endianness at compile-time,
or possibly at run-time although that will involve code-size
overheads.</P
><DIV
CLASS="NOTE"
><BLOCKQUOTE
CLASS="NOTE"
><P
><B
>Note: </B
>A related issue is that the current support for handling compiler
flags in the component framework is still limited and incapable of
handling flags at a very fine-grain. The support is likely to be
enhanced in future versions of the framework, but there are
non-trivial problems to be resolved.</P
></BLOCKQUOTE
></DIV
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="PACKAGE.SOURCE.INTERFACES">Package Interfaces and Implementations</H3
><P
>The component framework provides encapsulation at the package level. A
package <TT
CLASS="LITERAL"
>A</TT
> has no way of accessing the
implementation details of another package <TT
CLASS="LITERAL"
>B</TT
> at
compile-time. In particular, if there is a private header file
somewhere in a package's <TT
CLASS="FILENAME"
>src</TT
>
sub-directory then this header file is completely invisible to other
packages. Any attempts to cheat by using relative pathnames beginning
with <TT
CLASS="FILENAME"
>../..</TT
> are generally doomed
to failure because of the presence of package version directories.
There are two ways in which one package can affect another: by means
of the exported header files, which define a public interface; or via
the <SPAN
CLASS="APPLICATION"
>CDL</SPAN
> scripts.</P
><P
>This encapsulation is a deliberate aspect of the overall <SPAN
CLASS="APPLICATION"
>eCos</SPAN
>
component framework design. In most cases it does not cause any
problems for component writers. In some cases enforcing a clean
separation between interface and implementation details can improve
the code. Also it reduces problems when a package gets upgraded:
component writers are free to do pretty much anything on the
implementation side, including renaming every single source file; care
has to be taken only with the exported header files and with the <SPAN
CLASS="APPLICATION"
>CDL</SPAN
>
data, because those have the potential of impacting other packages.
Application code is similarly unable to access package implementation
details, only the exported interface.</P
><P
>Very occasionally the inability of one package to see implementation
details of another does cause problems. One example occurs in HAL
packages, where it may be desirable for the architectural, variant and
platform HAL's to share some information that should not be visible to
other packages or to application code. This may be addressed in the
future by introducing the concept of <TT
CLASS="LITERAL"
>friend</TT
>
packages, just as a C++ class can have <TT
CLASS="LITERAL"
>friend</TT
>
functions and classes which are allowed special access to a class
internals. It is not yet clear whether such cases are sufficiently
frequent to warrant introducing such a facility.</P
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="PACKAGE.SOURCE.CONFIG">Source Code and Configuration Options</H3
><P
>Configurability usually involves source code that needs to implement
different behavior depending on the settings of configuration
options. It is possible to write packages where the only consequence
associated with various configuration options is to control what gets
built, but this approach is limited and does not allow for
fine-grained configurability. There are three main ways in which
options could affect source code at build time:</P
><P
></P
><OL
TYPE="1"
><LI
><P
>The component code can be passed through a suitable preprocessor,
either an existing one such as <SPAN
CLASS="APPLICATION"
>m4</SPAN
> or a new one specially designed with
configurability in mind. The original sources would reside in the
component repository and the processed sources would reside in the
build tree. These processed sources can then be compiled in the usual
way.</P
><P
>This approach has two main advantages. First, it is independent from
the programming language used to code the components, provided
reasonable precautions are taken to avoid syntax clashes between
preprocessor statements and actual code. This would make it easier in
future to support languages other than C and C++. Second, configurable
code can make use of advanced preprocessing facilities such as loops
and recursion. The disadvantage is that component writers would have
to learn about a new preprocessor and embed appropriate directives in
the code. This makes it much more difficult to turn existing code into
components, and it involves extra training costs for the component
writers.</P
></LI
><LI
><P
>Compiler optimizations can be used to elide code that should not be
present, for example:</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
> …
if (CYGHWR_NUMBER_UARTS > 0) {
…
}
…</PRE
></TD
></TR
></TABLE
><P
>If the compiler knows that <TT
CLASS="VARNAME"
>CYGHWR_NUMBER_UARTS</TT
> is
the constant number 0 then it is a trivial operation to get rid of the
unnecessary code. The component framework still has to define this
symbol in a way that is acceptable to the compiler, typically by using
a <TT
CLASS="LITERAL"
>const</TT
> variable or a preprocessor symbol. In some
respects this is a clean approach to configurability, but it has
limitations. It cannot be used in the declarations of data structures
or classes, nor does it provide control over entire functions. In
addition it may not be immediately obvious that this code is affected
by configuration options, which may make it more difficult to
understand.</P
></LI
><LI
><P
>Existing language preprocessors can be used. In the case of C or C++
this would be the standard C preprocessor, and configurable code would
contain a number of <TT
CLASS="LITERAL"
>#ifdef</TT
> and
<TT
CLASS="LITERAL"
>#if</TT
> statements.</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>#if (CYGHWR_NUMBER_UARTS > 0)
…
#endif</PRE
></TD
></TR
></TABLE
><P
>This approach has the big advantage that the C preprocessor is a
technology that is both well-understood and widely used. There are
also disadvantages: it is not directly applicable to components
written in other languages such as Java (although it is possible to
use the C preprocessor as a stand-alone program); the preprocessing
facilities are rather limited, for example there is no looping
facility; and some people consider the technology to be ugly. Of
course it may be possible to get around the second objection by
extending the preprocessor that is used by gcc and g++.</P
></LI
></OL
><P
>The current component framework generates configuration header files
with C preprocessor <TT
CLASS="LITERAL"
>#define's</TT
> for each option
(typically, there various properties which can be used to control
this). It is up to component writers to decide whether to use
preprocessor <TT
CLASS="LITERAL"
>#ifdef</TT
> statements or language
constructs such as <TT
CLASS="LITERAL"
>if</TT
>. At present there is no
support for languages which do not involve the C preprocessor,
although such support can be added in future when the need arises.</P
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -