📄 package.sgml
字号:
</para><para>Very occasionally the inability of one package to see implementationdetails of another does cause problems. One example occurs in HALpackages, where it may be desirable for the architectural, variant andplatform HAL's to share some information that should not be visible toother packages or to application code. This may be addressed in thefuture by introducing the concept of <literal>friend</literal>packages, just as a C++ class can have <literal>friend</literal>functions and classes which are allowed special access to a classinternals. It is not yet clear whether such cases are sufficientlyfrequent to warrant introducing such a facility.</para></sect3><sect3 id="package.source.config"><title>Source Code and Configuration Options</title><para>Configurability usually involves source code that needs to implementdifferent behavior depending on the settings of configurationoptions. It is possible to write packages where the only consequenceassociated with various configuration options is to control what getsbuilt, but this approach is limited and does not allow forfine-grained configurability. There are three main ways in whichoptions could affect source code at build time:</para><orderedlist><listitem><para>The component code can be passed through a suitable preprocessor,either an existing one such as <applicationclass="software">m4</application> or a new one specially designed withconfigurability in mind. The original sources would reside in thecomponent repository and the processed sources would reside in thebuild tree. These processed sources can then be compiled in the usualway.</para><para>This approach has two main advantages. First, it is independent fromthe programming language used to code the components, providedreasonable precautions are taken to avoid syntax clashes betweenpreprocessor statements and actual code. This would make it easier infuture to support languages other than C and C++. Second, configurablecode can make use of advanced preprocessing facilities such as loopsand recursion. The disadvantage is that component writers would haveto learn about a new preprocessor and embed appropriate directives inthe code. This makes it much more difficult to turn existing code intocomponents, and it involves extra training costs for the componentwriters.</para></listitem><listitem><para>Compiler optimizations can be used to elide code that should not bepresent, for example:</para><programlisting width=72> … if (CYGHWR_NUMBER_UARTS > 0) { … } …</programlisting><para>If the compiler knows that <varname>CYGHWR_NUMBER_UARTS</varname> isthe constant number 0 then it is a trivial operation to get rid of theunnecessary code. The component framework still has to define thissymbol in a way that is acceptable to the compiler, typically by usinga <literal>const</literal> variable or a preprocessor symbol. In somerespects this is a clean approach to configurability, but it haslimitations. It cannot be used in the declarations of data structuresor classes, nor does it provide control over entire functions. Inaddition it may not be immediately obvious that this code is affectedby configuration options, which may make it more difficult tounderstand.</para></listitem><listitem><para>Existing language preprocessors can be used. In the case of C or C++this would be the standard C preprocessor, and configurable code wouldcontain a number of <literal>#ifdef</literal> and<literal>#if</literal> statements.</para><programlisting width=72>#if (CYGHWR_NUMBER_UARTS > 0) …#endif</programlisting><para>This approach has the big advantage that the C preprocessor is atechnology that is both well-understood and widely used. There arealso disadvantages: it is not directly applicable to componentswritten in other languages such as Java (although it is possible touse the C preprocessor as a stand-alone program); the preprocessingfacilities are rather limited, for example there is no loopingfacility; and some people consider the technology to be ugly. Ofcourse it may be possible to get around the second objection byextending the preprocessor that is used by gcc and g++.</para></listitem></orderedlist><para>The current component framework generates configuration header fileswith C preprocessor <literal>#define's</literal> for each option(typically, there various properties which can be used to controlthis). It is up to component writers to decide whether to usepreprocessor <literal>#ifdef</literal> statements or languageconstructs such as <literal>if</literal>. At present there is nosupport for languages which do not involve the C preprocessor,although such support can be added in future when the need arises.</para></sect3></sect2><!-- }}} --><!-- {{{ Headers --><sect2 id="package.headers"><title>Exported Header Files</title><para>A package's exported header files should specify the interfaceprovided by that package, and avoid any implementation details.However there may be performance or other reasons why implementationdetails occasionally need to be present in the exported headers.</para><note><para>Not all programming languages have the concept of a header file. Insome cases the component framework would need extensions to supportpackages written in such languages. </para></note><para>Configurability has a number of effects on the way exported headerfiles should be written. There may be configuration options whichaffect the interface of a package, not just the implementation. It isnecessary to worry about nested <literal>#include's</literal> and howthis affects package and application builds. A special case of thisrelates to whether or not exported header files should<literal>#include</literal> configuration headers. These configurationheaders are exported, but should only be <literal>#include'd</literal>when necessary.</para><sect3 id="package.headers.functions"><title>Configurable Functionality</title><para>Many configuration options affect only the implementation of apackage, not the interface. However some options will affect theinterface as well, which means that the options have to be tested inthe exported header files. Some implementation choices, for examplewhether or not a particular function should be inlined, also need tobe tested in the header file because of language limitations.</para><para>Consider a configuration option<varname>CYGFUN_KERNEL_MUTEX_TIMEDLOCK</varname> which controlswhether or not a function <function>cyg_mutex_timedlock</function> isprovided. The exported kernel header file <filenameclass="headerfile">cyg/kernel/kapi.h</filename> could contain thefollowing:</para><programlisting width=72>#include <pkgconf/kernel.h>…#ifdef CYGFUN_KERNEL_MUTEX_TIMEDLOCKextern bool cyg_mutex_timedlock(cyg_mutex_t*);#endif</programlisting><para>This is a correct header file, in that it defines the exact interfaceprovided by the package at all times. However is has a number ofimplications. First, the header file is now dependent on <filenameclass="headerfile">pkgconf/kernel.h</filename>, so any changes tokernel configuration options will cause <filenameclass="headerfile">cyg/kernel/kapi.h</filename> to be out of date, andany source files that use the kernel interface will need rebuilding.This may affect sources in the kernel package, in other packages, andin application source code. Second, if the application makes use ofthis function somewhere but the application developer hasmisconfigured the system and disabled this functionality anyway thenthere will now be a compile-time error when building the application.Note that other packages should not be affected, since they shouldimpose appropriate constraints on<varname>CYGFUN_KERNEL_MUTEX_TIMEDLOCK</varname> if they use thatfunctionality (although of course some dependencies like this may getmissed by component developers).</para><para>An alternative approach would be:</para><programlisting width=72>extern bool cyg_mutex_timedlock(cyg_mutex_t*);</programlisting><para>Effectively the header file is now lying about the functionalityprovided by the package. The first result is that there is no longer adependency on the kernel configuration header. The second result isthat an application file using the timed-lock function will nowcompile, but the application will fail to link. At this stage theapplication developer still has to intervene, change theconfiguration, and rebuild the system. However no applicationrecompilations are necessary, just a relink.</para><para>Theoretically it would be possible for a tool to analyze linker errorsand suggest possible configuration changes that would resolve theproblem, reducing the burden on the application developer. No suchtool is planned in the short term.</para><para>It is up to component writers to decide which of these two approachesshould be preferred. Note that it is not always possible to avoid<literal>#include'ing</literal> a configuration header file in anexported one, for example an option may affect a data structure ratherthan just the presence or absence of a function. Issues like this willvary from package to package.</para></sect3><sect3 id="package.headers.includes"><title>Nested <literal>#include's</literal></title><para>As a general rule, unnecessary <literal>#include's</literal> should beavoided. A header file should <literal>#include</literal> only thoseheader files which are absolutely needed for it to define itsinterface. Any additional <literal>#include's</literal> make it morelikely that package or application source files become dependent onconfiguration header files and will get rebuilt unnecessarily whenthere are minor configuration changes.</para></sect3><sect3 id="package.headers.configincludes"><title>Including Configuration Headers</title><para>Exported header files should avoid <literal>#include'ing</literal>configuration header files unless absolutely necessary, to avoidunnecessary rebuilding of both application code and other packageswhen there are minor configuration changes. A<literal>#include</literal> is needed only when a configuration optionaffects the exported interface, or when it affects some implementationdetails which is controlled by the header file such as whether or nota particular function gets inlined.</para><para>There are a couple of ways in which the problem of unnecessaryrebuilding could be addressed. The first would require moreintelligent handling of header file dependency handling by the tools(especially the compiler) and the build system. This would requirechanges to various non-eCos tools. An alternative approach would be tosupport finer-grained configuration header files, for example therecould be a file <filenameclass="headerfile">pkgconf/libc/inline.h</filename> controlling whichfunctions should be inlined. This could be achieved by some fairlysimple extensions to the component framework, but it makes it moredifficult to get the package header files and source code correct:a C preprocessor <literal>#ifdef</literal> directive does notdistinguish between a symbol not being defined because the option isdisabled, or the symbol not being defined because the appropriateconfiguration header file has not been <literal>#include'd</literal>.It is likely that a cross-referencing tool would have to be developedfirst to catch problems like this, before the component frameworkcould support finer-grained configuration headers.</para></sect3></sect2><!-- }}} --><!-- {{{ Documentation --><sect2 id="package.documentation"><title>Package Documentation</title><para>On-line package documentation should be in HTML format. The componentframework imposes no special limitations: component writers can decidewhich version of the HTML specification should be followed; they canalso decide on how best to cope with the limitations of differentbrowsers. In general it is a good idea to keep things simple.</para></sect2><!-- }}} --><!-- {{{ Tests --><sect2 id="package.tests"><title>Test Cases</title><para>Packages should normally come with one or more test cases. This allowsapplication developers to verify that a given package works correctlyon their particular hardware and in their particular configuration,making it slightly more likely that they will attempt to find bugs intheir own code rather than automatically blaming the componentwriters.</para><para>At the time of writing the application developer support for buildingand running test cases via the component framework is under review andlikely to change. Currently each test case should consist of a single
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -