[CMake] Add linker command file to object files

Michael Hertling mhertling at online.de
Wed Jul 13 19:25:59 EDT 2011


On 07/13/2011 10:56 AM, Florian Reinhard wrote:
> Hi!
> 
> Problem:
> I need to have a linker command file among the list of object files in
> a fixed order.
> 
> Setup:
> Cmake 2.8.5
> custom non-gnu texas instruments cl6x toolchain
> 
> Ideas:
> I figured that the object files list which one specifies as <objects>
> in CMAKE_C_LINK_EXECUTABLE are sorted in the way they are fed to
> "add_executable". So maybe one could treat a linker.cmd file as some
> fake object file?
> 
> Thank you,
> 
> Florian

The easiest workaround I know is to copy/symlink the linker.cmd file to
linker.cmd${CMAKE_C_OUTPUT_EXTENSION} via a custom command and mention
the result explicitly in ADD_EXECUTABLE(), e.g.:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(LINKERCOMMAND C)
SET(CMAKE_VERBOSE_MAKEFILE ON)
ADD_CUSTOM_COMMAND(
    OUTPUT linker.cmd${CMAKE_C_OUTPUT_EXTENSION}
    COMMAND ${CMAKE_COMMAND} -E create_symlink
        ${CMAKE_SOURCE_DIR}/linker.cmd
        linker.cmd${CMAKE_C_OUTPUT_EXTENSION})
FILE(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void){return 0;}\n")
ADD_EXECUTABLE(main main.c linker.cmd${CMAKE_C_OUTPUT_EXTENSION})

Usually, I'd set the EXTERNAL_OBJECT source file property on linker.cmd
to TRUE and expect that it can be mentioned immediately among main's
sources, i.e.

SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/linker.cmd
    PROPERTIES EXTERNAL_OBJECT TRUE)
...
ADD_EXECUTABLE(main main.c linker.cmd)

but this doesn't make linker.cmd appear in the linker command line.
AFAICS, the code in question resides in cmMakefileTargetGenerator::
WriteTargetBuildRules() from Source/cmMakefileTargetGenerator.cxx:

      if(!this->GlobalGenerator->IgnoreFile
         ((*source)->GetExtension().c_str()))
        {
        // Generate this object file's rule file.
        this->WriteObjectRuleFiles(*(*source));
        }
      else if((*source)->GetPropertyAsBool("EXTERNAL_OBJECT"))
        {
        // This is an external object file.  Just add it.
        this->ExternalObjects.push_back((*source)->GetFullPath());
        }
      else ...

This means that a source file can be added to the target's external
objects only if it's classified as "ignored" by cmGlobalGenerator::
IgnoreFile() from Source/cmGlobalGenerator.cxx:

bool cmGlobalGenerator::IgnoreFile(const char* l)
{
  if(this->GetLanguageFromExtension(l))
    {
    return false;
    }
  return (this->IgnoreExtensions.count(l) > 0);
}

The only possibility for this function to return true - and, thus, the
concerned file to be checked for the EXTERNAL_OBJECT property - is the
extension's appearance in the cmGlobalGenerator::IgnoreExtensions map,
but the latter is initialized once from CMAKE_<LANG>_IGNORE_EXTENSIONS
when the project's languages are enabled, and later changes don't have
any effect. Furthermore, CMAKE_<LANG>_IGNORE_EXTENSIONS is initialized
in Modules/CMake<LANG>Compiler.cmake.in without any user-accessible
parameter, so there's no chance to add an additional extension to
be ignored and the respective file subsequently checked for the
EXTERNAL_OBJECT property, if I'm not mistaken.

Hence, my question to the CMake developers: Is this behavior intended,
or should the check for the EXTERNAL_OBJECT property take precedence
over the examination of the source file's extension, i.e.:

      if((*source)->GetPropertyAsBool("EXTERNAL_OBJECT"))
        {
        // This is an external object file.  Just add it.
        this->ExternalObjects.push_back((*source)->GetFullPath());
        }
      else if(!this->GlobalGenerator->IgnoreFile
         ((*source)->GetExtension().c_str()))
        {
        // Generate this object file's rule file.
        this->WriteObjectRuleFiles(*(*source));
        }
      else ...

In this manner, a file marked as EXTERNAL_OBJECT appears in the linker
command in any case, which is, IMO, what the user does expect from the
EXTERNAL_OBJECT property's documentation. Alternatively, there should
be a possibility to enhance the list of extensions to be ignored, so
cmGlobalGenerator::IgnoreFile() can return true for a user-specified
file extension, or do I miss something? Of course, any comments are
greatly appreciated.

Regards,

Michael


More information about the CMake mailing list