?? compiler.cpp
字號:
// ----- compiler.cpp
#include "stdafx.h"
#include "Quincy.h"
#include "compiler.h"
#include "ErrorLogDialog.h"
Compiler* Compiler::pCompiler;
Compiler::Compiler()
{
m_bFoundDef = false;
m_bCpp = false;
m_bErrorCreated = false;
m_bLinkCpp = false;
m_bStopping = false;
m_CompileAction = none;
m_pdlgErrors = new CErrorLogDialog;
m_nErrorLogWidth = 0;
m_pConsoleApp = 0;
pCompiler = this;
}
Compiler::~Compiler()
{
delete m_pdlgErrors;
delete m_pConsoleApp;
pCompiler = 0;
}
void Compiler::ClearArrays()
{
m_SourceFiles.RemoveAll();
m_ObjectFiles.RemoveAll();
m_LibraryFiles.RemoveAll();
m_ResourceFiles.RemoveAll();
}
void Compiler::AddSourceFile(const CString& rstrSrc)
{
m_SourceFiles.Add(rstrSrc);
}
void Compiler::AddObjectFile(const CString& rstrObj)
{
m_ObjectFiles.Add(rstrObj);
}
void Compiler::AddResourceFile(const CString& rstrRc)
{
m_ResourceFiles.Add(rstrRc);
}
void Compiler::BuildTarget(const CString& strTargetName, CompileAction action)
{
m_bStopping = false;
if (theApp.IsOnCDROM(strTargetName)) {
std::string msg;
msg += const_cast<CString&>(strTargetName).GetBuffer(0);
msg += " is directed to a read-only medium (e.g. CD-ROM).",
AfxMessageBox(msg.c_str(), MB_ICONSTOP);
return;
}
m_CompileAction = action;
m_strTargetName = strTargetName;
m_strObjFiles.Empty();
m_strLibFiles.Empty();
ExitCode = 0;
CompileAllSources();
if (GatherObjects()) {
if (theApp.IsLibraryTarget())
BuildLibraryTarget();
else if (theApp.IsDLLTarget())
BuildDLLTarget();
else
BuildExeTarget();
}
if (cmds.size() > 0)
RunCompilerProgram(cmds.front().command);
}
void Compiler::CompileAllSources()
{
m_bFoundDef = false;
int nSize = m_SourceFiles.GetSize();
// --- compile the programs listed in the source code list
for (int n = 0; n < nSize; n++) {
CString strFile = m_SourceFiles[n];
if (strFile.IsEmpty())
break;
CompileOneSource(strFile);
}
}
void Compiler::CompileOneSource(const CString& strFile)
{
CString strCmd;
if (strFile.Right(4).CompareNoCase(".def") == 0) {
if (theApp.IsDLLTarget()) {
BuildDefCommand(strCmd, strFile);
m_bFoundDef = true;
}
else {
AfxMessageBox("Non-DLL project has .def file", MB_OK | MB_ICONQUESTION);
ExitCode = 1;
return;
}
}
else {
bool bRc = strFile.Right(3).CompareNoCase(".rc") == 0;
bool bRes = strFile.Right(4).CompareNoCase(".res") == 0;
m_bCpp = strFile.Right(4).CompareNoCase(".cpp") == 0;
m_bLinkCpp |= m_bCpp;
// ---- make a copy of the filename without the path
m_strFilename = theApp.GetFileName(strFile);
// ---- make a copy of the source file path and name without the file extension
CString strSrcPath = strFile.Left(strFile.GetLength()-((m_bCpp | bRes) ? 4 : (bRc ? 3 : 2)));
// ---- make a copy of the object file path without the filename
// (object files go where the exe file goes.)
int ndx = m_strTargetName.ReverseFind('\\');
if (ndx != -1)
m_strOPath = m_strTargetName.Left(ndx);
else {
char path[MAX_PATH];
_getcwd(path, MAX_PATH);
m_strOPath = path;
}
// ---- make a copy of the object file name
m_strOFile = MakeObjectFileName(strSrcPath);
// if the object file spec has no path info, add it
if (m_strOFile.Find("\\") == -1)
m_strOFile = m_strOPath + "\\" + m_strOFile;
if (bRc)
// ------ compiling a resource script (.rc) into object file
BuildResourceScriptCommand(strCmd);
else if (bRes)
// --- converting resource .res file into object file
BuildResFileCommand(strCmd);
else {
remove(m_strOFile);
BuildCompilerCommand(strCmd, strFile);
}
}
ScheduleProgram(strCmd);
}
int Compiler::GatherObjects()
{
int nSize = m_ObjectFiles.GetSize();
int n = 0;
if (nSize != 0) {
CString strFile;
while (n < nSize) {
strFile = m_ObjectFiles[n++];
if (strFile.IsEmpty())
break;
if (strFile.Find("\\") == -1)
strFile = m_strOPath + "\\" + strFile;
m_strObjFiles += theApp.Enquote(strFile) + " ";
}
}
return n;
}
void Compiler::BuildLibraryTarget()
{
CString strCmd;
BuildLibCommand(strCmd);
ScheduleProgram(strCmd);
}
void Compiler::BuildDLLTarget()
{
GatherLibraries();
CString strCmd;
BuildDLLCommand(strCmd);
if (!strCmd.IsEmpty())
ScheduleProgram(strCmd);
}
void Compiler::BuildExeTarget()
{
GatherLibraries();
CString strCmd;
BuildLinkerCommand(strCmd);
ScheduleProgram(strCmd, true);
}
void Compiler::GatherLibraries()
{
int nSize = m_LibraryFiles.GetSize();
CString strFile;
for (int n = 0; n < nSize; n++) {
strFile = m_LibraryFiles[n];
if (strFile.IsEmpty())
break;
m_strLibFiles += theApp.Enquote(strFile) + " ";
}
}
// --- schedules the execution of a compiler program (gcc, typically)
// the programs are run in the order they are scheduled from the OnIdle function
// if (depends) the scheduled program will not run if any prior program did not
// complete successfully, and it will remove all subsequent programs from the
// schedule.
void Compiler::ScheduleProgram(CString& strCmd, bool depends)
{
ConsoleCmd cmd;
cmd.command = strCmd;
cmd.dependent = depends;
cmds.push(cmd);
}
void Compiler::RunCompilerProgram(const CString& strCmd)
{
AddLogEntry(strCmd);
int ndx = strCmd.Find(' ');
ASSERT(ndx != -1);
CString strExe = strCmd.Left(ndx);
CString strArgs = strCmd.Right(strCmd.GetLength() - ndx);
delete m_pConsoleApp;
m_pConsoleApp = new ConsoleApp(strExe, &Notify, &Collect);
m_pConsoleApp->Run(strArgs);
}
void Compiler::ClearErrorLog()
{
if (m_bErrorCreated == true) {
ASSERT(m_pdlgErrors != 0);
CListBox* pList = static_cast<CListBox*>(m_pdlgErrors->GetDlgItem(IDC_ERRORLIST));
ASSERT(pList != 0);
pList->ResetContent();
m_nErrorLogWidth = 0;
}
MessageLog.clear();
}
void Compiler::CloseErrorLog()
{
ClearErrorLog();
if (m_bErrorCreated) {
ASSERT(m_pdlgErrors != 0);
m_pdlgErrors->ShowWindow(SW_HIDE);
}
}
void Compiler::AddLogEntry(const CString& str)
{
ASSERT(m_pdlgErrors != 0);
if (m_bErrorCreated != true) {
m_pdlgErrors->Create(IDD_ERRORLOG);
m_bErrorCreated = true;
}
m_pdlgErrors->ShowWindow(SW_SHOW);
CListBox* pList = static_cast<CListBox*>(m_pdlgErrors->GetDlgItem(IDC_ERRORLIST));
ASSERT(pList != 0);
CDC* pDC = pList->GetDC();
pList->AddString(str);
CSize size = pDC->GetTextExtent(str);
m_nErrorLogWidth = max(m_nErrorLogWidth, size.cx);
pList->SendMessage(LB_SETHORIZONTALEXTENT, m_nErrorLogWidth, 0);
MessageLog.push_back(str);
}
// --- called from the console application thread when compile program completes
void Compiler::Notify()
{
ASSERT(pCompiler != 0);
pCompiler->NotifyTermination();
}
void Compiler::NotifyTermination()
{
ASSERT(m_pConsoleApp != 0);
if (!m_bStopping && m_pConsoleApp->SuccessfulRun()) {
ExitCode |= m_pConsoleApp->Exitcode();
cmds.pop(); // pop off the command that just completed
if (cmds.size() > 0 && (ExitCode == 0 || cmds.front().dependent == false)) {
RunCompilerProgram(cmds.front().command);
return;
}
if (cmds.size() == 0 && ExitCode == 0) {
AddLogEntry("Successful build");
if (m_CompileAction != none) {
if (m_CompileAction == step)
theApp.DebugProgram(m_strTargetName, true);
else if (m_CompileAction == debug)
theApp.DebugProgram(m_strTargetName, false);
else
theApp.StartProgram(m_strTargetName);
m_CompileAction = none;
}
}
else
AddLogEntry("Unsuccessful build");
}
m_bStopping = false;
while (cmds.size() > 0)
cmds.pop();
// --- if this is a compile and link of only one IDE translation unit
// and no user library files are in the project (no project, actually),
// no need to keep the object file around.
if (!theApp.IsProjectFileLoaded())
remove(m_strOFile);
}
// --- called from the console application thread while compiling is going on
void Compiler::Collect(DWORD bufct)
{
ASSERT(pCompiler != 0);
pCompiler->CollectErrorMessages(bufct);
}
void Compiler::CollectErrorMessages(DWORD bufct)
{
char *buf = new char[bufct+1];
ASSERT(m_pConsoleApp != 0);
if (m_pConsoleApp->ReadConsole(buf, bufct) != 0)
AddLogEntry(buf);
delete buf;
}
void Compiler::Stop()
{
AddLogEntry("Build stopped by user");
m_bStopping = true;
if (m_pConsoleApp != 0)
m_pConsoleApp->Stop();
}
bool Compiler::CompileRunning() const
{
return m_pConsoleApp != 0 && m_pConsoleApp->IsRunning();
}
////////////////////////////////////////////////////////////////////////
//
// Specific compiler specializations of the abstract base Compiler class
//
////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
//
// GCCCompiler member functions
//
///////////////////////////////////////////////////////////////
void GCCCompiler::CompileAllSources()
{
m_strPrevLine.Empty();
Compiler::CompileAllSources();
}
void GCCCompiler::CompileOneSource(const CString& strFile)
{
const_cast<CString&>(strFile).MakeLower(); // gcc 2.95.1 bug
Compiler::CompileOneSource(strFile);
}
void GCCCompiler::AddLibraryFile(const CString& rstrLib)
{
if (rstrLib.Left(3).CompareNoCase("lib") == 0) {
CString strLib("-l");
strLib += rstrLib.Mid(3, rstrLib.GetLength()-5);
m_LibraryFiles.Add(strLib);
}
else
m_LibraryFiles.Add(rstrLib);
}
void GCCCompiler::BuildResourceScriptCommand(CString& strCmd)
{
strCmd = theApp.Enquote(theApp.ToolsPath() + "windres.exe");
for (int i = 0; i < theApp.GetDefinesArray().GetSize(); i++) {
strCmd += " -D";
strCmd += theApp.GetDefinesArray()[i];
}
strCmd += " ";
strCmd += theApp.Enquote(m_strFilename);
strCmd += " ";
strCmd += theApp.Enquote(m_strOFile);
}
void GCCCompiler::BuildResFileCommand(CString& strCmd)
{
strCmd = theApp.Enquote(theApp.ToolsPath() + "windres.exe");
strCmd += " -i ";
strCmd += theApp.Enquote(m_strFilename);
strCmd += " -o ";
strCmd += theApp.Enquote(m_strOFile);
}
void GCCCompiler::BuildCompilerCommand(CString& strCmd, const CString& strFile)
{
strCmd = theApp.Enquote(theApp.ToolsPath() + "gcc.exe");
if (theApp.IsAddingDebugInfo())
strCmd += " -g";
if (!theApp.IsAddingDebugInfo() && theApp.OptimizeLevel()) {
strCmd += " -O";
char oc = '0' + theApp.OptimizeLevel();
strCmd += oc;
}
if (m_bCpp) {
if (!theApp.IncludeRTTI())
strCmd += " -fno-rtti";
if (!theApp.IncludeExceptions())
strCmd += " -fno-exceptions";
}
if (theApp.StrictANSI())
strCmd += " -pedantic-errors";
int i;
for (i = 0; i < theApp.GetIncludeArray().GetSize(); i++) {
strCmd += " -I";
strCmd += theApp.Enquote(theApp.GetIncludeArray()[i]);
}
if (theApp.IsGUITarget()) {
strCmd += " -I";
strCmd += theApp.Enquote(theApp.QuincyInstallPath() + "\\include");
strCmd += " -mwindows";
}
if (theApp.IsDLLTarget())
strCmd += " -mdll";
for (i = 0; i < theApp.GetDefinesArray().GetSize(); i++) {
strCmd += " -D";
strCmd += theApp.GetDefinesArray()[i];
}
strCmd += " -o ";
strCmd += theApp.Enquote(m_strOFile);
strCmd += " -c ";
strCmd += theApp.CmdLineOptions() + " ";
strCmd += theApp.Enquote(strFile);
}
void GCCCompiler::BuildLibCommand(CString& strCmd)
{
strCmd = theApp.Enquote(theApp.ToolsPath() + "ar");
strCmd += " rc ";
strCmd += theApp.Enquote(m_strTargetName);
strCmd += " ";
strCmd += m_strObjFiles;
}
void GCCCompiler::BuildDLLCommand(CString& strCmd)
{
if (!m_bFoundDef) {
AfxMessageBox("DLL project has no .def file", MB_OK | MB_ICONSTOP);
return;
}
// ------ build dll
GatherLibraries();
strCmd = theApp.Enquote(theApp.ToolsPath() + "dllwrap.exe") + " -o ";
strCmd += theApp.Enquote(theApp.GetFileName(m_strTargetName)); // name of the dll
strCmd += " --def ";
strCmd += theApp.Enquote(m_strDefname); // name of the def
GetLibraryPaths(strCmd);
strCmd += m_strObjFiles;
strCmd += " ";
strCmd += m_strLibFiles;
GetGUILibraries(strCmd);
}
void GCCCompiler::BuildDefCommand(CString& strCmd, const CString& strFile)
{
int ndx = m_strTargetName.ReverseFind('\\');
// --- build the path to the import library
CString strImportPath = m_strTargetName.Left(ndx+1);
CString strImportName = m_strTargetName.Right(m_strTargetName.GetLength() - (ndx+1));
CString strImportLib = strImportPath + "lib" + strImportName.Left(strImportName.GetLength() - 3) + "a";
m_strDefname = strImportPath + strFile;
strCmd = theApp.Enquote(theApp.ToolsPath() + "dlltool.exe");
strCmd += " --dllname ";
strCmd += theApp.Enquote(theApp.GetFileName(m_strTargetName)); // name of the dll
strCmd += " --def ";
strCmd += theApp.Enquote(m_strDefname); // name of the def
strCmd += " --output-lib ";
strCmd += theApp.Enquote(strImportLib); // name of the import lib
}
void GCCCompiler::GetLibraryPaths(CString& strCmd)
{
int i;
for (i = 0; i < theApp.GetLibraryArray().GetSize(); i++) {
strCmd += " -L";
strCmd += theApp.Enquote(theApp.GetLibraryArray()[i]);
}
strCmd += " ";
}
void GCCCompiler::GetGUILibraries(CString& strCmd)
{
strCmd += " -luser32 -lgdi32 -lcomdlg32 -lwinmm -lcomctl32 -lctl3d32 ";
}
void GCCCompiler::BuildLinkerCommand(CString& strCmd)
{
strCmd = theApp.Enquote(theApp.ToolsPath() + "gcc.exe");
if (theApp.IsGUITarget())
strCmd += " -mwindows";
strCmd += " -o ";
strCmd += theApp.Enquote(m_strTargetName) + " ";
if (!theApp.IsAddingDebugInfo())
strCmd += "-s ";
GetLibraryPaths(strCmd);
strCmd += m_strObjFiles;
strCmd += " ";
strCmd += m_strLibFiles;
if (m_bLinkCpp)
strCmd += " -lstdc++";
if (theApp.IsGUITarget())
GetGUILibraries(strCmd);
}
bool GCCCompiler::GetMessageData(int sel, CString& strFile, int& line)
{
bool rtn = false;
if (MessageLog.size() > sel) {
CString& msg = MessageLog[sel];
const char* cp = msg.GetBuffer(0);
for (int n = 0; n < msg.GetLength(); n++) {
if (*(cp+n) == ':') {
if (isdigit(*(cp+n+1))) {
rtn = true;
strFile = msg.Left(n);
line = atoi(cp+n+1);
break;
}
}
}
}
return rtn;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -