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
This commit is contained in:
Alexander Neundorf 2007-05-25 15:22:22 -04:00
parent 1ed238c7f5
commit f4eb541880
11 changed files with 419 additions and 53 deletions

View File

@ -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"

View File

@ -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 "

View File

@ -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$)

View File

@ -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"

View File

@ -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__)

View File

@ -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. "

View File

@ -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;
}

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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