cxBuild.h

// cxBuild.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2006

#ifndef Ceda_Build_cxBuild_cxBuild_H
#define Ceda_Build_cxBuild_cxBuild_H

#if defined(_WIN32) && !defined(__WINE__) && !defined(cxBuild_STATIC_LIBRARY)
    #ifdef cxBuild_IS_COMPILING
        // While compiling the library, export symbols
        #define cxBuild_API __declspec(dllexport)
    #else
        // While #including puboic headers of the library, import symbols
        #define cxBuild_API __declspec(dllimport)
    #endif
#else 
    #define cxBuild_API
#endif

#include "Ceda/cxMacroExpander/Mpfw.h"
#include "Ceda/cxUtils/xvector.h"
#include "Ceda/cxUtils/xstring.h"
#include "Ceda/cxUtils/SubString.h"
#include "Ceda/cxUtils/CedaSdkVersion.h"
#include <map>
#include <list>

namespace ceda
{
#define CEDA_XCPP_VERSION "Xcpp V" CedaSdk_VERSION_STR " (" CedaSdk_VERSION_BUILDTIME ")"

#define ROOT_MARKER_FILENAME ".xcwsroot"

cxBuild_API bool SplitPath(SubString filePath, SubString& rootPath, SubString& pathFromRoot);

// Indicates which compiler
enum ECompiler
{
    XC_VC6,
    XC_VC8,         // VC2005  _MSC_VER 1400
    XC_VC9,         // VC2008  _MSC_VER 1500
    XC_VC10,        // VC2010  _MSC_VER 1600
    XC_VC11,        // VC2012  _MSC_VER 1700
    XC_VC12,        // VC2013  _MSC_VER 1800
    XC_VC14,        // VC2014  _MSC_VER 1900
    XC_GCC,         // gcc, g++
    XC_WINEGCC,     // winegcc, wineg++
    XC_CLANG,       // clang, clang++
    XC_COUNT
};

// Returns true for XC_VC6,XC_VC8,XC_VC9,XC_VC10,XC_VC11,XC_VC12,XC_VC14
cxBuild_API bool IsMsvcCompiler(ECompiler c);

// Returns true for XC_GCC,XC_WINEGCC,XC_CLANG
cxBuild_API bool IsGccBasedCompiler(ECompiler c);

cxBuild_API ConstStringZ CompilerToString(ECompiler c);

// Write Directories in the style used by xcpj files to the given ostream using the given indent
// dirPath is the path (relative to the current directory) for the first directory to be processed
// dirName is the name of that directory
// projName is the name of the project
cxBuild_API void GenerateXcpj(SubString projName, SubString dirName, SubString dirPath, xostream& os, ssize_t indent = 0);

cxBuild_API void GenerateXcpjs(SubString dirPath);

cxBuild_API bool ValidatePath(SubString path);

enum EXcppMode
{
    XM_CLEAN,
    XM_COMPILE,
    XM_BUILD,
    XM_GEN_PROJECT_FILES,
    XM_SHOW_TRANSLATED_FILE,
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// SearchAndReplacer

/*
Performs in-place search and replace on a given string passed by reference in the constructor.
Finalise() must be called at the end to ensure the replacements take affect.
*/

class cxBuild_API SearchAndReplacer
{
public:
    SearchAndReplacer(xstring& s);
    void Replace(const xstring& search, const xstring& replace);
    void Replace(const std::map<xstring, xstring>& vars);
    void Finalise();

private:
    xstring& m_s;
    xstring m_t;
    bool m_in_s;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// EnvironmentVariables 

struct cxBuild_API EnvironmentVariables
{
    //bool Validate(xostream& os) const;
    void Write(xostream& os) const;
    //const xstring& GetEnviromment() const;
    void Put() const;

    xstring m_pathVariable;
    xstring m_includeVariable;
    xstring m_libVariable;

private:
    // Derived settings
    //mutable xstring m_environment;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// XcppBuildSettings

struct cxBuild_API XcppBuildSettings
{
    XcppBuildSettings();

    // Returns true if valid, else writes an error message to 'os' and returns false.
    bool Validate(xostream& os) const;

    bool PathsAreValid() const;

    // Assuming current directory is the 'build' folder, search for the file with the
    // given logical path in the virtual tree.  Returns true if successful and writes the
    // local path to the physical tree containing the file to localPathToRoot and the
    // local path to the file to 'localPathToFile'.
    bool ResolveLogicalPath(
        const xstring& logicalPathToFile, 
        xstring& localPathToRoot, 
        xstring& localPathToFile) const;
    
    // Assuming current directory is the 'build' folder, search for the file with the
    // given logical path in the virtual tree.  Returns true if successful and writes the
    // local path to the file to 'localPath'.
    bool ResolveLogicalPath(const xstring& logicalPath, xstring& localPath) const;

    bool ResolveImportPath(const xstring& importPath, xstring& localPath) const;

    // Get the environment variables for this platform, or NULL if not defined
    EnvironmentVariables* GetEnvironVariables();
    const EnvironmentVariables* GetEnvironVariables() const
    { 
        return const_cast<XcppBuildSettings*>(this)->GetEnvironVariables(); 
    }
    void PutEnvironVariables() const;
    void PutEnvironVariablesForAnyPlatform() const;

    bool GenerateMsvcDeclSpecImportExport() const
    {
        return m_systemName == "Windows";
    }
    
    ///////////////////////////// State //////////////////////////
    
    MpfwSourceFileList m_srcFileList;
    MpfwFrame m_mpfwFrame;
    
    // The ordered sequence of local paths to roots of physical trees that define the
    // virtual tree.
    xvector<xstring> m_virtualTree;
    
    // Path relative to build folder for where to write libraries and executables
    // Comes from the $EXPORT_LIB variable
    xstring m_pathToExportLibsDir;          // Typically "../lib"

    // Path relative to build folder for where to write the translated headers which are in normal C++
    // Comes from the $EXPORT_TRANSLATED_INCLUDE variable
    xstring m_pathToExportTranslatedIncludesDir;      // Typically "../include"

    // Path relative to build folder for where to write original untranslated headers which are in xC++
    // Comes from the $EXPORT_UNTRANSLATED_INCLUDE variable
    xstring m_pathToExportUntranslatedIncludesDir;  // Typically "../export"
    
    xvector<xstring> m_vectorOfPathRootToXcws;  // Eg ["Ceda/cxObject/Object.xcws"]
    xstring m_systemName;                       // Comes from CMAKE_SYSTEM_NAME, e.g. "Windows", "Linux", or "Android"
    xstring m_systemProcessor;                  // Comes from CMAKE_SYSTEM_PROCESSOR, e.g. "x86", "AMD64", "armv7l", "armv8a"
    xstring m_systemVersion;                    // Comes from CMAKE_SYSTEM_VERSION, e.g. "10.0.18362"
    xstring m_sizeofPointer;                    // Comes from CMAKE_SIZEOF_VOID_P, e.g. "4" or "8"
    xstring m_platform;                         // E.g. "Win32"    
    xstring m_configName;                       // E.g. "Debug" or "Release"
    
    xstring m_localPathOfFileToCompile;
    
    bool m_defaultToDll;    // default to DLL versus static library
    bool m_diagnostics;
    ECompiler m_compiler;
    bool m_targetXP;
    bool m_translateOnly;
    bool m_rebuildAll;
    bool m_writeTokenEquivalent;
    bool m_exportPublicHeaders;
    bool m_repackageExecutableTargets;
    bool m_solutionContainsPrepackagedProjects;
    bool m_makeTranslatedFilesReadOnly;
    bool m_makeExportedHeaderFilesReadOnly;
    EXcppMode m_mode;
    
    // Mapping from platform to environment variables for that platform
    std::map<xstring, EnvironmentVariables> m_environVarsMap;
};

cxBuild_API bool ProcessXcppConfigFile(
    XcppBuildSettings& settings, 
    ConstStringZ configPath, 
    SubString extra);

/*
Given a xcpj file,  generate all the cpp and h files under the bin folder.  These files will
subsequently be built in the normal way using VC++.

The C++ language extensions involve the use of 

1)  a powerful pre-processor (the "macro expander") - implemented in the cxMacroExpander.dll

2)  Special C++ extensions to support interfaces,  the ceda object model, reflection etc.

Steps

1.  Open and parse the xcpj file.

2.  Process each file in the xcpj file

    For each file

        *   Open the file
        *   Run the preprocessor
        *   Run the C++ extensions

    The result is that each file is added to a map keyed by name.  Eg name = "IEngine.h"  Note that
    the name includes the extension, but not the path of directories containing the file.
*/

// Must be called when the current working directory is the 'bin' folder
cxBuild_API bool ReadXcwsAndBuildAllProjects(XcppBuildSettings& bs);

} // namespace ceda

#endif // include guard