Ver Fonte

ENH: make the compiler id detection work, even if the output file name of
the compiler is completely unknown and even if it produces intel hex or
motorola s-record files, with test

Alex

Alexander Neundorf há 18 anos atrás
pai
commit
f4eb541880

+ 2 - 7
Modules/CMakeCCompilerId.c

@@ -41,14 +41,9 @@
 
 /* sdcc, the small devices C compiler for embedded systems, 
    http://sdcc.sourceforge.net 
-   Beside this id not supported yet by CMake 
-   Unfortunately this doesn't work because SDCC (and other embedded compilers 
-   too) produce not binary files, but e.g. Intel hex files by default. 
-   This also means it has a different suffix (.ihx) so the file isn't even
-   found. */
-/*
+   Beside this id not supported yet by CMake. */
 #elif defined(SDCC)
-# define COMPILER_ID "SDCC" */
+# define COMPILER_ID "SDCC"
 
 #elif defined(_COMPILER_VERSION)
 # define COMPILER_ID "MIPSpro"

+ 37 - 41
Modules/CMakeDetermineCompilerId.cmake

@@ -66,56 +66,52 @@ MACRO(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
       "${CMAKE_${lang}_COMPILER_ID_SRC}\" succeeded with the following output:\n"
       "${CMAKE_${lang}_COMPILER_ID_OUTPUT}\n\n")
 
-    # Find the executable produced by the compiler.
-    SET(CMAKE_${lang}_COMPILER_ID_EXE)
-    GET_FILENAME_COMPONENT(CMAKE_${lang}_COMPILER_ID_SRC_BASE ${CMAKE_${lang}_COMPILER_ID_SRC} NAME_WE)
-    FOREACH(name a.out a.exe ${CMAKE_${lang}_COMPILER_ID_SRC_BASE}.exe)
-      IF(EXISTS ${CMAKE_${lang}_COMPILER_ID_DIR}/${name})
-        SET(CMAKE_${lang}_COMPILER_ID_EXE ${CMAKE_${lang}_COMPILER_ID_DIR}/${name})
-      ENDIF(EXISTS ${CMAKE_${lang}_COMPILER_ID_DIR}/${name})
-    ENDFOREACH(name)
-
-    # Check if the executable was found.
-    IF(CMAKE_${lang}_COMPILER_ID_EXE)
-      # The executable was found.
+    # Find the executable produced by the compiler, try all files in the binary dir
+    SET(CMAKE_${lang}_COMPILER_ID)
+    FILE(GLOB COMPILER_${lang}_PRODUCED_FILES ${CMAKE_${lang}_COMPILER_ID_DIR}/*)
+    FOREACH(CMAKE_${lang}_COMPILER_ID_EXE ${COMPILER_${lang}_PRODUCED_FILES})
       FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Compilation of the ${lang} compiler identification source \""
         "${CMAKE_${lang}_COMPILER_ID_SRC}\" produced \""
         "${CMAKE_${lang}_COMPILER_ID_EXE}\"\n\n")
+      # only check if we don't have it yet 
+      IF(NOT CMAKE_${lang}_COMPILER_ID)
+        # Read the compiler identification string from the executable file.
+        FILE(STRINGS ${CMAKE_${lang}_COMPILER_ID_EXE}
+          CMAKE_${lang}_COMPILER_ID_STRINGS LIMIT_COUNT 2 REGEX "INFO:")
+        FOREACH(info ${CMAKE_${lang}_COMPILER_ID_STRINGS})
+          IF("${info}" MATCHES ".*INFO:compiler\\[([^]]*)\\].*")
+            STRING(REGEX REPLACE ".*INFO:compiler\\[([^]]*)\\].*" "\\1"
+              CMAKE_${lang}_COMPILER_ID "${info}")
+          ENDIF("${info}" MATCHES ".*INFO:compiler\\[([^]]*)\\].*")
+          IF("${info}" MATCHES ".*INFO:platform\\[([^]]*)\\].*")
+            STRING(REGEX REPLACE ".*INFO:platform\\[([^]]*)\\].*" "\\1"
+              CMAKE_${lang}_PLATFORM_ID "${info}")
+          ENDIF("${info}" MATCHES ".*INFO:platform\\[([^]]*)\\].*")
+        ENDFOREACH(info)
 
-      # Read the compiler identification string from the executable file.
-      FILE(STRINGS ${CMAKE_${lang}_COMPILER_ID_EXE}
-        CMAKE_${lang}_COMPILER_ID_STRINGS LIMIT_COUNT 2 REGEX "INFO:")
-      FOREACH(info ${CMAKE_${lang}_COMPILER_ID_STRINGS})
-        IF("${info}" MATCHES ".*INFO:compiler\\[([^]]*)\\].*")
-          STRING(REGEX REPLACE ".*INFO:compiler\\[([^]]*)\\].*" "\\1"
-            CMAKE_${lang}_COMPILER_ID "${info}")
-        ENDIF("${info}" MATCHES ".*INFO:compiler\\[([^]]*)\\].*")
-        IF("${info}" MATCHES ".*INFO:platform\\[([^]]*)\\].*")
-          STRING(REGEX REPLACE ".*INFO:platform\\[([^]]*)\\].*" "\\1"
-            CMAKE_${lang}_PLATFORM_ID "${info}")
-        ENDIF("${info}" MATCHES ".*INFO:platform\\[([^]]*)\\].*")
-      ENDFOREACH(info)
+        # Check the compiler identification string.
+        IF(CMAKE_${lang}_COMPILER_ID)
+          # The compiler identification was found.
+          FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+            "The ${lang} compiler identification is ${CMAKE_${lang}_COMPILER_ID}, found in \""
+            "${CMAKE_${lang}_COMPILER_ID_EXE}\"\n\n")
+        ELSE(CMAKE_${lang}_COMPILER_ID)
+          # The compiler identification could not be found.
+          FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+            "The ${lang} compiler identification could not be found in \""
+            "${CMAKE_${lang}_COMPILER_ID_EXE}\"\n\n")
+        ENDIF(CMAKE_${lang}_COMPILER_ID)
+      ENDIF(NOT CMAKE_${lang}_COMPILER_ID)
+    ENDFOREACH(CMAKE_${lang}_COMPILER_ID_EXE)
 
-      # Check the compiler identification string.
-      IF(CMAKE_${lang}_COMPILER_ID)
-        # The compiler identification was found.
-        FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
-          "The ${lang} compiler identification is ${CMAKE_${lang}_COMPILER_ID}\n\n")
-      ELSE(CMAKE_${lang}_COMPILER_ID)
-        # The compiler identification could not be found.
-        FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
-          "The ${lang} compiler identification could not be found in \""
-          "${CMAKE_${lang}_COMPILER_ID_EXE}\"\n\n")
-      ENDIF(CMAKE_${lang}_COMPILER_ID)
-    ELSE(CMAKE_${lang}_COMPILER_ID_EXE)
-      # The executable was not found.
+    IF(NOT COMPILER_${lang}_PRODUCED_FILES)
+      # No executable was found.
       FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Compilation of the ${lang} compiler identification source \""
         "${CMAKE_${lang}_COMPILER_ID_SRC}\" did not produce an executable in "
-        "${CMAKE_${lang}_COMPILER_ID_DIR} "
-        "with a name known to CMake.\n\n")
-    ENDIF(CMAKE_${lang}_COMPILER_ID_EXE)
+        "${CMAKE_${lang}_COMPILER_ID_DIR} .\n\n")
+    ENDIF(NOT COMPILER_${lang}_PRODUCED_FILES)
 
     IF(CMAKE_${lang}_COMPILER_ID)
       MESSAGE(STATUS "The ${lang} compiler identification is "

+ 1 - 1
Modules/CMakeLists.txt

@@ -1,5 +1,5 @@
 # just install the modules
-# new file added, force rerunning cmake #
+# new file added, force rerunning cmake 
 
 SUBDIRS(Platform)
 INSTALL_FILES(${CMAKE_DATA_DIR}/Modules .*\\.cmake$)

+ 2 - 1
Source/cmBootstrapCommands.cxx

@@ -30,6 +30,7 @@
 #include "cmBuildCommand.cxx"
 #include "cmCMakeMinimumRequired.cxx"
 #include "cmConfigureFileCommand.cxx"
+#include "cmCoreTryCompile.cxx"
 #include "cmCreateTestSourceList.cxx"
 #include "cmElseCommand.cxx"
 #include "cmEnableTestingCommand.cxx"
@@ -47,6 +48,7 @@
 #include "cmGetCMakePropertyCommand.cxx"
 #include "cmGetFilenameComponentCommand.cxx"
 #include "cmGetSourceFilePropertyCommand.cxx"
+#include "cmHexFileConverter.cxx"
 #include "cmIfCommand.cxx"
 #include "cmIncludeCommand.cxx"
 #include "cmIncludeDirectoryCommand.cxx"
@@ -66,7 +68,6 @@
 #include "cmStringCommand.cxx"
 #include "cmSubdirCommand.cxx"
 #include "cmTargetLinkLibrariesCommand.cxx"
-#include "cmCoreTryCompile.cxx"
 #include "cmTryCompileCommand.cxx"
 #include "cmTryRunCommand.cxx"
 

+ 10 - 0
Source/cmFileCommand.cxx

@@ -15,6 +15,8 @@
 
 =========================================================================*/
 #include "cmFileCommand.h"
+#include "cmake.h"
+#include "cmHexFileConverter.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -414,6 +416,14 @@ bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
       return false;
       }
     }
+    
+  std::string binaryFileName = this->Makefile->GetCurrentOutputDirectory();
+  binaryFileName += cmake::GetCMakeFilesDirectory();
+  binaryFileName += "/FileCommandStringsBinaryFile";
+  if (cmHexFileConverter::TryConvert(fileName.c_str(), binaryFileName.c_str()))
+    {
+    fileName = binaryFileName;
+    }
 
   // Open the specified file.
 #if defined(_WIN32) || defined(__CYGWIN__)

+ 4 - 3
Source/cmFileCommand.h

@@ -93,9 +93,10 @@ public:
       "want to generate input files to CMake.\n"
       "READ will read the content of a file and store it into the "
       "variable.\n"
-      "STRINGS will parse a list of ASCII strings from a file and store it "
-      "in a variable. Binary data in the file are ignored. Carriage return "
-      "(CR) characters are ignored. "
+      "STRINGS will parse a list of ASCII strings from a binary file and "
+      "store it in a variable. Binary data in the file are ignored. Carriage "
+      "return (CR) characters are ignored. It works also for Intel Hex and "
+      "Motorola S-record files.\n "
       "LIMIT_COUNT sets the maximum number of strings to return. "
       "LIMIT_INPUT sets the maximum number of bytes to read from "
       "the input file. "

+ 266 - 0
Source/cmHexFileConverter.cxx

@@ -0,0 +1,266 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmHexFileConverter.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define INTEL_HEX_MIN_LINE_LENGTH     (1+8        +2)
+#define INTEL_HEX_MAX_LINE_LENGTH     (1+8+(256*2)+2)
+#define MOTOROLA_SREC_MIN_LINE_LENGTH (2+2+4        +2)
+#define MOTOROLA_SREC_MAX_LINE_LENGTH (2+2+8+(256*2)+2)
+
+// might go to SystemTools ?
+static bool cm_IsHexChar(char c)
+{
+  return (((c >= '0') && (c <= '9')) 
+         || ((c >= 'a') && (c <= 'f')) 
+         || ((c >= 'A') && (c <= 'F')));
+}
+
+static unsigned int ChompStrlen(const char* line)
+{
+  if (line == 0)
+    {
+    return 0;
+    }
+  unsigned int length = strlen(line);
+  if ((line[length-1] == '\n') || (line[length-1] == '\r'))
+    {
+    length--;
+    }
+  if ((line[length-1] == '\n') || (line[length-1] == '\r'))
+    {
+    length--;
+    }
+  return length;
+}
+
+static bool OutputBin(FILE* file, const char * buf, 
+                      unsigned int startIndex, unsigned int stopIndex)
+{
+  bool success = true;
+  char hexNumber[3];
+  hexNumber[2] = '\0';
+  char outBuf[256];
+  int outBufCount = 0;
+  for (unsigned int i = startIndex; i < stopIndex; i += 2)
+    {
+    hexNumber[0] = buf[i];
+    hexNumber[1] = buf[i+1];
+    unsigned int convertedByte = 0;
+    if (sscanf(hexNumber, "%x", &convertedByte) != 1)
+      {
+      success = false;
+      break;
+      }
+    outBuf[outBufCount] = convertedByte & 0xff;
+    outBufCount++;
+    }
+  if (success)
+    {
+    success = (fwrite(outBuf, 1, outBufCount, file)==outBufCount);
+    }
+  return success;
+}
+
+// see http://www.die.net/doc/linux/man/man5/srec.5.html
+static bool ConvertMotorolaSrecLine(const char* buf, FILE* outFile)
+{
+  unsigned int slen = ChompStrlen(buf);
+  if ((slen < MOTOROLA_SREC_MIN_LINE_LENGTH) 
+       || (slen > MOTOROLA_SREC_MAX_LINE_LENGTH))
+    {
+    return false;
+    }
+
+  // line length must be even
+  if (slen % 2 == 1)
+    {
+    return false;
+    }
+
+  if (buf[0] != 'S')
+    {
+    return false;
+    }
+
+  unsigned int dataStart = 0;
+  // ignore extra address records
+  if ((buf[1] == '5') || (buf[1] == '7') || (buf[1] == '8') || (buf[1] == '9'))
+    {
+    return true;
+    }
+  else if (buf[1] == '1')
+    {
+    dataStart = 8;
+    }
+  else if (buf[1] == '2')
+    {
+    dataStart = 10;
+    }
+  else if (buf[1] == '3')
+    {
+    dataStart = 12;
+    }
+  else // unknown record type
+    {
+    return false;
+    }
+
+  // ignore the last two bytes  (checksum)
+  return OutputBin(outFile, buf, dataStart, slen - 2);
+}
+
+// see http://en.wikipedia.org/wiki/Intel_hex
+static bool ConvertIntelHexLine(const char* buf, FILE* outFile)
+{
+  unsigned int slen = ChompStrlen(buf);
+  if ((slen < INTEL_HEX_MIN_LINE_LENGTH) 
+       || (slen > INTEL_HEX_MAX_LINE_LENGTH))
+    {
+    return false;
+    }
+
+  // line length must be odd
+  if (slen % 2 == 0)
+    {
+    return false;
+    }
+
+  if ((buf[0] != ':') || (buf[7] != '0'))
+    {
+    return false;
+    }
+
+  unsigned int dataStart = 0;
+  if ((buf[8] == '0') || (buf[8] == '1'))
+    {
+    dataStart = 9;
+    }
+  // ignore extra address records
+  else if ((buf[8] == '2') || (buf[8] == '3') || (buf[8] == '4') || (buf[8] == '5'))
+    {
+    return true;
+    }
+  else  // unknown record type
+    {
+    return false;
+    }
+
+// ignore the last two bytes  (checksum)
+  return OutputBin(outFile, buf, dataStart, slen - 2);
+}
+
+cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType(
+                                                        const char* inFileName)
+{
+  char buf[1024];
+  FILE* inFile = fopen(inFileName, "rb");
+  if (inFile == 0)
+    {
+    return Binary;
+    }
+
+  fgets(buf, 1024, inFile);
+  fclose(inFile);
+  FileType type = Binary;
+  unsigned int minLineLength = 0;
+  unsigned int maxLineLength = 0;
+  if (buf[0] == ':') // might be an intel hex file
+    {
+    type = IntelHex;
+    minLineLength = INTEL_HEX_MIN_LINE_LENGTH;
+    maxLineLength = INTEL_HEX_MAX_LINE_LENGTH;
+    }
+  else if (buf[0] == 'S') // might be a motorola srec file
+    {
+    type = MotorolaSrec;
+    minLineLength = MOTOROLA_SREC_MIN_LINE_LENGTH;
+    maxLineLength = MOTOROLA_SREC_MAX_LINE_LENGTH;
+    }
+  else
+    {
+    return Binary;
+    }
+
+  int slen = ChompStrlen(buf);
+  if ((slen < minLineLength) || (slen > maxLineLength))
+    {
+    return Binary;
+    }
+
+  for (unsigned int i = 1; i < slen; i++)
+    {
+    if (!cm_IsHexChar(buf[i]))
+      {
+      return Binary;
+      }
+    }
+  return type;
+}
+
+bool cmHexFileConverter::TryConvert(const char* inFileName,
+                                    const char* outFileName)
+{
+  FileType type = DetermineFileType(inFileName);
+  if (type == Binary)
+    {
+    return false;
+    }
+
+  // try to open the file
+  FILE* inFile = fopen(inFileName, "rb");
+  FILE* outFile = fopen(outFileName, "wb");
+  if ((inFile == 0) || (outFile == 0))
+    {
+    if (inFile != 0)
+      {
+      fclose(inFile);
+      }
+    if (outFile != 0)
+      {
+      fclose(outFile);
+      }
+    return false;
+    }
+
+  // convert them line by line
+  bool success = false;
+  char buf[1024];
+  while (fgets(buf, 1024, inFile) != 0)
+    {
+    if (type == MotorolaSrec)
+      {
+      success = ConvertMotorolaSrecLine(buf, outFile);
+      }
+    else if (type == IntelHex)
+      {
+      success = ConvertIntelHexLine(buf, outFile);
+      }
+    if (success == false)
+      {
+      break;
+      }
+    }
+
+  // close them again
+  fclose(inFile);
+  fclose(outFile);
+  return success;
+}
+

+ 33 - 0
Source/cmHexFileConverter.h

@@ -0,0 +1,33 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmHexFileConverter_h
+#define cmHexFileConverter_h
+
+/** \class cmHexFileConverter
+ * \brief Can detects Intel Hex and Motorola S-record files and convert them 
+ *        to binary files.
+ *
+ */
+class cmHexFileConverter
+{
+public:
+  enum FileType {Binary, IntelHex, MotorolaSrec};
+  static FileType DetermineFileType(const char* inFileName);
+  static bool TryConvert(const char* inFileName, const char* outFileName);
+};
+
+#endif

+ 22 - 0
Tests/StringFileTest/CMakeLists.txt

@@ -16,6 +16,28 @@ ELSE("${infile_strings}" STREQUAL "${infile_strings_goal}")
     "FILE(STRINGS) incorrectly read [${infile_strings}]")
 ENDIF("${infile_strings}" STREQUAL "${infile_strings_goal}")
 
+
+# test that FILE(STRINGS) also work with Intel hex and Motorola S-record files
+# this file has been created with "sdcc main.c"
+FILE(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/main.ihx" infile_strings REGEX INFO)
+SET(infile_strings_goal "INFO:compiler\\[SDCC-HEX\\]")
+IF("${infile_strings}" MATCHES "${infile_strings_goal}")
+  MESSAGE("FILE(STRINGS) correctly read from hex file [${infile_strings}]")
+ELSE("${infile_strings}" MATCHES "${infile_strings_goal}")
+  MESSAGE(SEND_ERROR
+    "FILE(STRINGS) incorrectly read from hex file [${infile_strings}]")
+ENDIF("${infile_strings}" MATCHES "${infile_strings_goal}")
+
+# this file has been created with "sdcc main.c --out-fmt-s19"
+FILE(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/main.srec" infile_strings REGEX INFO)
+SET(infile_strings_goal "INFO:compiler\\[SDCC-SREC\\]")
+IF("${infile_strings}" MATCHES "${infile_strings_goal}")
+  MESSAGE("FILE(STRINGS) correctly read from srec file [${infile_strings}]")
+ELSE("${infile_strings}" MATCHES "${infile_strings_goal}")
+  MESSAGE(SEND_ERROR
+    "FILE(STRINGS) incorrectly read from srec file [${infile_strings}]")
+ENDIF("${infile_strings}" MATCHES "${infile_strings_goal}")
+
 # String test
 STRING(REGEX MATCH "[cC][mM][aA][kK][eE]" rmvar "CMake is great")
 STRING(REGEX MATCHALL "[cC][mM][aA][kK][eE]" rmallvar "CMake is better than cmake or CMake")

+ 21 - 0
Tests/StringFileTest/main.ihx

@@ -0,0 +1,21 @@
+:03000000020003F8
+:03005C0002005F40
+:05005F0012006480FEA8
+:010064002279
+:0E006900494E464F3A636F6D70696C65725B6D
+:0A007700534443432D4845585D00F3
+:06003200E478FFF6D8FDA2
+:080010007900E94400601B7A4D
+:0500180000900081785A
+:03001D000075A0CB
+:0A00200000E493F2A308B800020503
+:08002A00A0D9F4DAF275A0FF81
+:080038007800E84400600A7939
+:030040000075A0A8
+:0600430000E4F309D8FC03
+:080049007800E84400600C7926
+:0B00510000900000E4F0A3D8FCD9FAF6
+:03000300758107FD
+:0A000600120065E582600302005F4E
+:04006500758200227E
+:00000001FF

+ 21 - 0
Tests/StringFileTest/main.srec

@@ -0,0 +1,21 @@
+S1060000020003F4
+S106005C02005F3C
+S108005F12006480FEA4
+S10400642275
+S1110069494E464F3A636F6D70696C65725B69
+S10E0077534443432D535245435D00A6
+S1090032E478FFF6D8FD9E
+S10B00107900E94400601B7A49
+S1080018009000827855
+S106001D0075A0C7
+S10D002000E493F2A308B8000205FF
+S10B002AA0D9F4DAF275A0FF7D
+S10B00387800E84400600A7935
+S10600400075A0A4
+S109004300E4F309D8FCFF
+S10B00497800E84400600C7922
+S10E005100900000E4F0A3D8FCD9FAF2
+S1060003758107F9
+S10D0006120065E582600302005F4A
+S1070065758200227A
+S9030000FC