Frequently Asked Questions for the porting engineer

 

Check also this page to remember the porting effort overview and this page for the step-by-step instructions for adding new platform support.

Back to Porting engineer
Back to SBuild manual home

Table of content
Configuration per target platform

Why does it tell that a target is not configured for my target platform?

Let's assume this is your situation: You added the support for new platform to SBuild/SCons; you know it works because you compile and link OK some example code; and yet you get an SBuild error when you try to build the entire product.

Answer: the errors like "Target not configured for this platform" will come up on purpose, for you to discover one by one the places where the author of the original product decided to do special things for each target platform. This is a feature, not a bug. You may try to shut up all those places in one move using the so-called default platform support.

Back to top

Which files do I have to touch for my target platform support?

First, you make sure that the platform is supported in the SBuild tool (see here) and then that the build scripts of your product are informed (see here).

About the second part: The errors like  "Target not configured for this platform" doesn't tell you in which file exactly you must do a change, should you decide to fix it right away. We do not recommend that you jump to change one file like that. You probably want to first inspect the output of -T option for your top build. It gives the complete tree of the targets that you build and you may already start to see, from the type of the targets, which ones are likely to need changes. The tree also gives you in which build script each target is.  Check also here for more details on how to find and how to change the relevant build scripts in your SBuild project.

Back to top

Do I have to touch absolutely all those target specifications?

If customization of targets have been extensively used in your SBuild project, then you are left to touch many targets, likely all the build scripts. You may wonder if you have to go through this chore.

Answer: No, if your platform is similar to an already supported one, you are lucky: you only need a 1 line addition in 1 file. This is the default platform support mechanism.  

Back to top

I did take care of my targets for my platform and it still complains. Why?

Answer: mind what you build! Quite frequently, such errors comes from running a larger build than what is actually intended. In that case SBuild will complain about not-yet-ported targets you don't care about. For example, one situation we saw frequently: a porting engineer adds support for a target platform that doesn't support dynamic libraries, then happily triggers a large build that somewhere, among other targets, builds a dynamic library and then he looks puzzled at the error message. Do not build the default target in the build script if this is not what you really want. Provide the tgt=<target_id> keyword argument to identify that static library that you want to build by itself. Note that the careful build script author may use the Boolean function sb.dll_supported() to change the default target in the build script (as a courtesy to deep embedded porting).

You normally use -T to see exactly what do you build. If that doesn't work for you (the error comes too soon for -T to show anything) then run -T for another target platform (you normally have a reference platform before you start your port, one platform where the build works fine). 

Back to top

Why do they tell me that I broke the build for other platforms with my changes?

Answer: There is still a remote possibility to break a build for another platform during a port. This happens when:

  • you introduce a new attribute *_per_platform to a target or
  • you introduce a new prebuilt external (sb.E() and use_sdks target attribute)

The second situation is rarer. Let's focus on the first. If you introduce the attribute ccppdefines_per_platform, for example, to a target and you place in it an entry only for your target platform, other people may get the error message that this place was not configured for their platform. So the trivial advice is to look around in the script you are changing and then add empty entries for all the target platforms that you see already mentioned in that script. Another (better) way is to use empty platform support (just list the platform name in the default platform support list) for all those platforms that you want to be "immune" to later changes for other platforms.

Back to top

Where can I change the target platform?

You can change tgtplatform, toolchain and bldopt, like all variants, on the command line (ex. tgtplatform=armv4i_wce500) or in the shell environment (ex. set SBUILD_CCP_TGTPLATFORM=armv4i_wce500).

You can also change variants in the _sb_custom.py file of your SBuild project. Here is an example:

if sb.get_host() in ["calvin", "jerom", "hobbes", "helga"]:
    tgtplatform = "sparc_solaris"
    toolchain = "gcc"

This code makes that on a host named calvin, for example, the build will be performed for the platform sparc_solaris, without any keyword argument on the command line.

Take care, if you decide to change in this way, say tgtplatform, then you should NOT test and act on the current value of it in _sb_custom.py or _sb_vars.py, like in the following code:

if sb.vars.tgtplatform.get() == 'sparc_solaris':
    impl_dbg = 'none'
    concat_usage = 0
elif sb.vars.tgtplatform.get() == 'ti_c55':
    impl_heap = 'heapembedded'
    concat_usage = 0
....

If you want such customization code (see also here for other examples), you should use only the command line or the shell environment to change the values of the C/C++ variants, tgtplatform, toolchain and bldopt. Here is the code to place at the very bottom of _sb_custom.py that will make sure than no attempt to change them is made.

# we make sure that tgtplatform, toolchain and bldopt are not assigned in this file
# because we use them already in _sb_vars (which is parsed first)
_forbidden_customizations = ["tgtplatform", "toolchain", "bldopt"]
assert not any(
                [x in sys.modules[__name__].__dict__ for x in _forbidden_customizations]
       ), "Such customizations are not allowed because already used before the customization step"

Back to top

Position independent and position dependent code (PIC and PDC)

What is PIC and PDC? Why do I care?

Answer: PIC stands for "Position Independent Code" and it means object code compiled with the proper options to be relocatable (not restricted to any given address when loaded in memory for execution). PDC means "Position Dependent Code" and it is the opposite of PIC. On many platforms, the distinction PIC vs. PDC is not relevant because only one flavor is always used.

You do care because some popular compilers, like the GNU C compiler, make this distinction, meaning they produce 2 flavors of code and these flavors better not be mixed up when linking everything together. SBuilds try to hide this aspect from most users (with more or less success) but as a porting engineer you do care because SCons made the choice to keep separate compiler command line for PIC and PDC.

Back to top

Why bother with the difference between PDC and PIC? What is a static library with dynamic library code?

Answer: The PIC is slightly slower at run-time because of one more pointer operation when accessing code and/or data. This makes that some tool chain and some platform authors fanatically defend PDC.

Also, SCons was considering the difference between the two in an attempt to make sure that no PDC ends up in dynamic libraries which on some platforms will result in a fatal link error. That is a nasty SCons feature, meaning that, attempting to solve an issue for a fraction of users, it inflicts a pain on most users (also because, without target platform and without variant concepts, SCons had to implement it as an awkward exception).

So what is a static library for a dynamic library? Since the compiled object code has flavors it goes also that static libraries have flavors. A static library may contain PDC (and that is meant to be linked in a dynamic library) or PDC (and that cannot be linked in a dynamic library, for platforms where the difference counts). That distinction between different static libraries comes as a shock for many inexperienced developers.

Note that, apart from the PDC and PIC, there are other situations where C/C++ compiled code has flavors that should be stored separately and not mixed up. For example, for the Microsoft Win 32 platform, the -M*** options to the compiler (which actually are indications for the linker) produce .obj files that shouldn't be mixed up in the same link.

Back to top

How do I tell that I don't really care about the difference between PDC and PIC?

Answer: For SBuild, this is a one line change in the file ccpp_vars.py. For example, you can write:

   tgtplatform.inhibatePDCvsPICcheck['my_own_plat'] =  1  
This code says that the my_own_plat target platform doesn't care. It doesn't matter if your platform supports only PIC or only PDC, you will do the same thing in ccpp_vars.py.

After we implemented SBuild, SCons came up with its own setting to tell that. It is the Construction Environment variable named STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME (yes, it's the longest name in the Construction Environment). "Shared objects" are PIC and "static objects" are PDC. You can set this in your SCons Tool. Know that if the SBuild inhibatePDCvsPICcheck and SCons STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME disagree, you get a warning and the SBuild one is kept (because the SCons has no target platform concept and then the SCons setting may apply too broadly).

This being sad, this setting should be automatic. The two compiler command lines should be compared internally and any difference should conclude that PDC and PIC is not the same.

Back to top

How do I learn if my platform cares about the difference between PDC and PIC?

Answer: When compiling C/C++ code, PIC or PDC is a choice that shows up as a compiler command line switch. If your C compiler has such a switch, the difference between PIC and PDC may be relevant for you (but it's not mandatory). The popular GNU C/C++ compiler has the option -fPIC. Yet, it may very well be that this tool chain is used for a target platform that only uses PIC. Such platforms are: MS Windows, Sparc Solaris, IBM AIX, etc.

Back to top

Avoiding the command line length limitation

What is the command line length limitation?

The Microsoft Windows as build platform suffers from one annoying limitation of the cmd.exe shell. It only supports command lines of no more than 2kb before variable expansion and no more than 4kb after variable expansion. SBuild/SCons let you push the limit to 32kb by using the Win 32 API to fork processes but that doesn't work always (some toolchains desperately need a shell). The Unix shells, including the cygwin bash, are better than cmd.exe but they usually stop as well at the 32kb barrier.

Note that the limit that you can use in practice is slightly lower because SCons quotes file names on the command line. Check the comments in the source file win32.py.

If you run into such limitation during your build, you'll likely get some obscure error (cmd.exe just tells that the executable exited with error code 1, the Win 32 CreateProcess tells that the command is incorrect). You don't get any information pointing to what is wrong.

Back to top

What do I have to change to avoid command line length limitation?

Traditionally, the issue is solved with command line indirection. That is a technique where the command line arguments are put in a temporary file (sometimes called response file) and the name of that file is put on the real command line. If the executables of your tool chain accept a command line indirection, then SCons knows how to automatically indirect long command lines, like many other build tools.

In order to do that you need to change your Construction Environment. Precisely, you need to change members of the Construction Environment that are command lines that are at risk to become too long. The command lines for the linker and for the archiver are the first candidates.

As a reminder, the names of construction environment members that are command lines are ending with "COM". Here are some examples:

  • LINKCOM: the command line used to link position dependent code
  • SHLINKCOM: the command line used to link position independent code
  • ARCOM: the command line used to archive position dependent code
  • SHARCOM: the command line used to archive position independent code
  • CCCOM: the command line used to compiled position dependent C code
  • SHCCCOM: the command line used to compiled position independent C code
  • CXXCOM: the command line used to compiled position dependent C++ code
  • SHCXXCOM: the command line used to compiled position independent C++ code
  • and others: lint, ...

Back to top

How do I provide command line indirection?

SCons solution is to "wrap" the command lines so that a temporary file is created automatically when the line is too long. This wrapping is achieved by adding ${TEMPFILE( ... )} around the original command line as in the following example for the C compiler command line:

        env['CCCOM']  = '${TEMPFILE("$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES")}'
The original command line, non protected, was the following
        env['CCCOM']  = "$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES"

Behind this $TEMPFILE there is a Python class, TempFileMunge, implemented in the source file win32.py. If your executable has some different requirements for the temporary file, like a given prefix or a given extension, then you need to subclass TempFileMunge in your own SCons Tool. That subclass will reimplement the __init__() to change settings like the command line switch to precede the name of the temporary file. Take as example the class LintFileMunge in the SCons Tool lint.py (made for the Gimpel Lint).

Note that, because of some SCons bug, the temporary files are not always properly deleted and they tend to accumulate (in whatever is your MS Windows temporary files directory).

Back to top

What to do if my tool chain does not support command line indirection?

If your tool chain doesn't have the feature (some poor ports of gcc, for example) and you don't have the possibility to put pressure on the provider to add it, then you are in a bad shape. Manual processing will be required.

Your first attempt should be to switch to the 32kb limit (use cygwin python or use the Win 32 API which is default if you have Win32 Python extensions installed or ActivePython). With this limit is very likely that all compilation command lines will pass and only some archiving and linking command lines will still hit the wall. If you only ship static libraries, you're saved: you can archive manually (copy the compiled objects in one place or don't copy but archive incrementally). If you need to link, you can still try several manual trick:

  • copy all needed files in one place
  • archive first and link from libraries only
  • drop the exported symbols list (just export all)

If you don't find any way to get beyond the 4kb cmd.exe limit, then it is probably a good idea to put this tool chain in the trash can, where it belongs, and move to a more recent tool chain for the same product.

Back to top

Back to Porting engineer
Back to SBuild manual home