Version 1.0

Still need to add the clean script for linux
master
Joeyrp 4 years ago
parent 04a24a6ac3
commit 2b4724df1c

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.16.3) cmake_minimum_required(VERSION 3.16.3)
# Set the project name and version # Set the project name and version
project(cgen VERSION 0.1.0) project(cgen VERSION 1.0.0)
# specify the C++ standard # specify the C++ standard
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
@ -9,6 +9,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(cgenConfig.h.in cgenConfig.h) configure_file(cgenConfig.h.in cgenConfig.h)
# specify the project source files
set( CGEN_SRC set( CGEN_SRC
src/main.cpp src/main.cpp
src/utils/CmdArgParser.cpp src/utils/CmdArgParser.cpp

@ -9,9 +9,9 @@ IF not exist build/ (
IF "%~1" == "r" ( IF "%~1" == "r" (
cmake --build build/ --target ALL_BUILD --config Release cmake --build build/ --target ALL_BUILD --config Release
) ELSE ( ) ELSE (
cmake --build build/ --target ALL_BUILD --config Debug cmake --build build/ --target ALL_BUILD --config Debug
) )
:END :END

@ -6,18 +6,422 @@
* Description - Generates a new C++ project with CMake * Description - Generates a new C++ project with CMake
******************************************************************************/ ******************************************************************************/
// TODO: Generate a clean.sh script for linux
#include <utils/CmdArgParser.h> #include <utils/CmdArgParser.h>
#include <utils/StringManip.h> #include <utils/StringManip.h>
#include <iostream> #include <iostream>
#include <filesystem>
#include <string>
#include <fstream>
#include <ctime>
typedef jpUtils::CmdArgParser::ArgDesc ArgDesc; typedef jpUtils::CmdArgParser::ArgDesc ArgDesc;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
jpUtils::CmdArgParser argParser(argc, argv, "Generates a new C++ project with CMake"); jpUtils::CmdArgParser argParser(argc, argv, "Generates a new C++ project with CMake.");
// Required args
argParser.AddArg(ArgDesc("ProjectName", false, 1, "The name of the project to generate."));
// Options
argParser.AddArg(ArgDesc("-h", true, 0, "Displays this help messasge."));
argParser.AddArg(ArgDesc("-v", true, 0, "Verbose - Print extra info while running."));
argParser.AddArg(ArgDesc("-p", true, 1, "Platform - Can be one of: win, linux, both. Default is win."));
argParser.AddArg(ArgDesc("-l", true, 1, "License - Generate an MIT license file with the given name."));
argParser.AddArg(ArgDesc("-d", true, 1, "Path to the location to generate the project at. Defaults to the current dirctory."));
argParser.AddArg(ArgDesc("-i", true, 0, "Generate a .gitignore file"));
argParser.AddArg(ArgDesc("-m", true, 1, "Specify the CMake version to require. Default is 3.16.3"));
argParser.AddArg(ArgDesc("-c", true, 1, "Specify the C++ version to require. Default is 17"));
bool result = argParser.Parse();
if (!result)
{
if (argParser.ContainsOption("-h"))
{
std::cout << argParser.GetUsageText() << std::endl;
return 0;
}
else
{
std::cout << argParser.GetErrorMessage();
std::cout << "\n" << argParser.GetUsageText() << std::endl;
return 1;
}
}
////////////////////////////////////////////////////////////
// Generate directory structure
////////////////////////////////////////////////////////////
std::filesystem::path root = std::filesystem::current_path();
if (argParser.ContainsOption("-d"))
{
if (std::filesystem::exists(argParser.GetOptionValue("-d").values[0]))
{
root = argParser.GetOptionValue("-d").values[0];
}
}
std::cout << "\nGenerating project at location: " << root.string().c_str();
std::string project_name = argParser.GetPositionalArg(0).values[0];
root /= std::filesystem::path(project_name);
if (!std::filesystem::create_directory(root))
{
std::cout << "\nCould not create directory: " << root.string().c_str();
return 1;
}
if (!std::filesystem::create_directory(root / "build"))
{
std::cout << "\nCould not create build directory";
return 1;
}
if (!std::filesystem::create_directory(root / "scripts"))
{
std::cout << "\nCould not create scripts directory";
return 1;
}
if (!std::filesystem::create_directory(root / "src"))
{
std::cout << "\nCould not create src directory";
return 1;
}
////////////////////////////////////////////////////////////
// Generate CMake files
////////////////////////////////////////////////////////////
std::filesystem::path cmake_file = root / std::filesystem::path("CMakeLists.txt");
std::ofstream ofs(cmake_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the CMake file: " << cmake_file.string().c_str();
return 1;
}
std::cout << "\nGenerating CMake file: " << cmake_file.string().c_str();
std::string cmversion = "3.16.3";
if (argParser.ContainsOption("-m"))
{
cmversion = argParser.GetOptionValue("-m").values[0];
}
std::string cversion = "17";
if (argParser.ContainsOption("-c"))
{
cversion = argParser.GetOptionValue("-c").values[0];
}
ofs << "cmake_minimum_required(VERSION " << cmversion << ")";
ofs << "\n\n# set the project name and version";
ofs << "\nproject(" << project_name << " VERSION 0.1.0)";
ofs << "\n\n# specify the C++ standard";
ofs << "\nset(CMAKE_CXX_STANDARD " << cversion << ")";
ofs << "\nset(CMAKE_CXX_STANDARD_REQUIRED True)";
ofs << "\n\nconfigure_file(" << project_name << "Config.h.in " << project_name << "Config.h)";
ofs << "\n\n# specify the project source files";
ofs << "\nset( " << jpUtils::StringManip::ToUpper(project_name) << "_SRC";
ofs << "\n\tsrc/main.cpp";
ofs << "\n)";
ofs << "\n\n# add the executable";
ofs << "\nadd_executable(${PROJECT_NAME} ${" << jpUtils::StringManip::ToUpper(project_name) << "_SRC})";
ofs << "\n\ntarget_include_directories(${PROJECT_NAME}";
ofs << "\n\tPUBLIC \"${PROJECT_BINARY_DIR}\"";
ofs << "\n\tPUBLIC src";
ofs << "\n)";
ofs.close();
ofs.clear();
////////////////////////////////////////////////////////////
// Generate Config file
////////////////////////////////////////////////////////////
std::string config_name = project_name;
config_name += "Config.h.in";
std::filesystem::path config_file = root / config_name;
ofs = std::ofstream(config_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the Config file: " << config_file.string().c_str();
return 1;
}
std::cout << "\nGenerating Config file: " << config_file.string().c_str();
ofs << "#define " << project_name << "_VERSION_MAJOR @" << project_name << "_VERSION_MAJOR@";
ofs << "\n#define " << project_name << "_VERSION_MINOR @" << project_name << "_VERSION_MINOR@";
ofs << "\n#define " << project_name << "_VERSION_PATCH @" << project_name << "_VERSION_PATCH@";
ofs.close();
ofs.clear();
////////////////////////////////////////////////////////////
// Generate License file
////////////////////////////////////////////////////////////
if (argParser.ContainsOption("-l"))
{
std::filesystem::path license_file = root / "LICENSE";
ofs = std::ofstream(license_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the License file: " << license_file.string().c_str();
return 1;
}
std::cout << "\nGenerating License file: " << license_file.string().c_str();
time_t now = time(0);
tm *gmtm = gmtime(&now);
ofs << "Copyright " << gmtm->tm_year + 1900 <<" " << argParser.GetOptionValue("-l").values[0];
ofs << "\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:";
ofs << "\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.";
ofs << "\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.";
ofs.close();
ofs.clear();
}
////////////////////////////////////////////////////////////
// Generate .gitignore file
////////////////////////////////////////////////////////////
if (argParser.ContainsOption("-i"))
{
std::filesystem::path ignore_file = root / ".gitignore";
ofs = std::ofstream(ignore_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the .gitignore file: " << ignore_file.string().c_str();
return 1;
}
std::cout << "\nGenerating .gitignore file: " << ignore_file.string().c_str();
ofs << "######################## VSCODE IGNORES";
ofs << "\n.vscode/";
ofs << "\n";
ofs << "\n";
ofs << "\n######################## C++ IGNORES";
ofs << "\n# Prerequisites";
ofs << "\n*.d";
ofs << "\n";
ofs << "\n# Compiled Object files";
ofs << "\n*.slo";
ofs << "\n*.lo";
ofs << "\n*.o";
ofs << "\n*.obj";
ofs << "\n";
ofs << "\n# Precompiled Headers";
ofs << "\n*.gch";
ofs << "\n*.pch";
ofs << "\n";
ofs << "\n# Compiled Dynamic libraries";
ofs << "\n*.so";
ofs << "\n*.dylib";
ofs << "\n*.dll";
ofs << "\n";
ofs << "\n# Fortran module files";
ofs << "\n*.mod";
ofs << "\n*.smod";
ofs << "\n";
ofs << "\n# Compiled Static libraries";
ofs << "\n*.lai";
ofs << "\n*.la";
ofs << "\n*.a";
ofs << "\n*.lib";
ofs << "\n";
ofs << "\n# Executables";
ofs << "\n*.exe";
ofs << "\n*.out";
ofs << "\n*.app";
ofs << "\n";
ofs << "\n# other";
ofs << "\n*.log";
ofs << "\n*.zip";
ofs << "\n*.ini";
ofs << "\n";
ofs << "\n######################## CMAKE IGNORES";
ofs << "\nCMakeLists.txt.user";
ofs << "\nCMakeCache.txt";
ofs << "\nCMakeFiles";
ofs << "\nCMakeScripts";
ofs << "\nTesting";
ofs << "\nMakefile";
ofs << "\ncmake_install.cmake";
ofs << "\ninstall_manifest.txt";
ofs << "\ncompile_commands.json";
ofs << "\nCTestTestfile.cmake";
ofs << "\n_deps";
ofs << "\n";
ofs << "\n######################## BUILD IGNORES";
ofs << "\nbuild/";
ofs.close();
ofs.clear();
}
////////////////////////////////////////////////////////////
// Generate Script files
////////////////////////////////////////////////////////////
bool have_platform_option = argParser.ContainsOption("-p");
bool gen_windows = (!have_platform_option || (argParser.GetOptionValue("-p").values[0] == "win" || argParser.GetOptionValue("-p").values[0] == "both"));
bool gen_linux = (have_platform_option && (argParser.GetOptionValue("-p").values[0] == "linux" || argParser.GetOptionValue("-p").values[0] == "both"));
std::filesystem::path script_dir = root / "scripts";
if (gen_windows)
{
// CONFIG
std::filesystem::path config_file = script_dir / "config.bat";
ofs = std::ofstream(config_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the config script file: " << config_file.string().c_str();
return 1;
}
std::cout << "\nGenerating config script file: " << config_file.string().c_str();
ofs << "@echo off";
ofs << "\nREM This script expects to be run from the parent directory";
ofs << "\nREM ex. scripts/cmconfig.bat";
ofs << "\n@echo off";
ofs << "\n\ncmake -Wno-dev -B build/ -S . -G \"Visual Studio 16 2019\" -A x64";
ofs.close();
ofs.clear();
// BUILD
std::filesystem::path build_file = script_dir / "build.bat";
ofs = std::ofstream(build_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the build script file: " << build_file.string().c_str();
return 1;
}
std::cout << "\nGenerating build script file: " << build_file.string().c_str();
ofs << "@echo off";
ofs << "\nREM This script expects to be run from the parent directory";
ofs << "\nREM ex. scripts/build.bat";
ofs << "\n\nIF not exist build/ (";
ofs << "\n\techo This script needs to be run from the directory above build/";
ofs << "\n\tgoto END";
ofs << "\n)";
ofs << "\n\nIF \"%~1\" == \"r\" (";
ofs << "\n\tcmake --build build/ --target ALL_BUILD --config Release";
ofs << "\n) ELSE (";
ofs << "\n\tcmake --build build/ --target ALL_BUILD --config Debug";
ofs << "\n)";
ofs << "\n\n:END";
ofs.close();
ofs.clear();
// CLEAN
std::filesystem::path clean_file = script_dir / "clean.bat";
ofs = std::ofstream(clean_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the clean script file: " << clean_file.string().c_str();
return 1;
}
std::cout << "\nGenerating clean script file: " << clean_file.string().c_str();
ofs << "@echo off";
ofs << "\n\nIF not exist build/ (";
ofs << "\n\techo This script needs to be run from the directory above build/";
ofs << "\n\tgoto END";
ofs << "\n)";
ofs << "\n\necho Removing the build directory";
ofs << "\ndel /s /q build";
ofs << "\nrd /s /q build";
ofs << "\n\n:END";
ofs.close();
ofs.clear();
}
if (gen_linux)
{
// CONFIG
std::filesystem::path config_file = script_dir / "config.sh";
ofs = std::ofstream(config_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the config script file: " << config_file.string().c_str();
return 1;
}
std::cout << "\nGenerating config script file: " << config_file.string().c_str();
ofs << "#! /bin/sh";
ofs << "\n# This script expects to be run from the parent directory";
ofs << "\n# ex. scripts/cmconfig.sh";
ofs << "\n\ncmake -Wno-dev -DBOX2D_BUILD_TESTBED=OFF -S . -B build/";
ofs.close();
ofs.clear();
// BUILD
std::filesystem::path build_file = script_dir / "build.sh";
ofs = std::ofstream(build_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the build script file: " << build_file.string().c_str();
return 1;
}
std::cout << "\nGenerating build script file: " << build_file.string().c_str();
ofs << "#! /bin/sh";
ofs << "\n# This script expects to be run from the parent directory";
ofs << "\n# ex. scripts/build.sh";
ofs << "\n\nmake -C build/";
ofs.close();
ofs.clear();
}
////////////////////////////////////////////////////////////
// Generate Main.cpp
////////////////////////////////////////////////////////////
std::filesystem::path main_file = root / "src/main.cpp";
ofs = std::ofstream(main_file.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the config script file: " << main_file.string().c_str();
return 1;
}
std::cout << "\nGenerating config script file: " << main_file.string().c_str();
ofs << "\n\n#include <iostream>";
ofs << "\n#include <" << project_name << "Config.h>";
ofs << "\n\nint main(int argc, char** argv)";
ofs << "\n{";
ofs << "\n\tstd::cout << \"Hello, World!\";";
ofs << "\n\tstd::cout << \"\\nThis is version: \" << " << project_name << "_VERSION_MAJOR << \".\" << " << project_name << "_VERSION_MINOR << \".\" << " << project_name << "_VERSION_PATCH;";
ofs << "\n\treturn 0;";
ofs << "\n}";
ofs.close();
ofs.clear();
std::cout << "\n\nNew project generated!";
return 0; return 0;
} }

@ -70,7 +70,8 @@ namespace jpUtils
return false; return false;
} }
auto iter = mExpectedOptArgs.find(std::string(mArgv[i])); std::string temp = mArgv[i];
auto iter = mExpectedOptArgs.find(temp);
if (iter == mExpectedOptArgs.end()) if (iter == mExpectedOptArgs.end())
{ {
mErrorMessage += "\nUknown Argument: " + std::string(mArgv[i]); mErrorMessage += "\nUknown Argument: " + std::string(mArgv[i]);

@ -14,6 +14,43 @@
namespace jpUtils namespace jpUtils
{ {
std::string StringManip::ToUpper(std::string str)
{
std::string result = "";
for (int i = 0; i < (signed)str.length(); i++)
{
if (str[i] >= 97 && str[i] <= 122)
{
result += str[i] - 32;
}
else
{
result += str[i];
}
}
return result;
}
std::string StringManip::ToLower(std::string str)
{
std::string result = "";
for (int i = 0; i < (signed)str.length(); i++)
{
if (str[i] >= 65 && str[i] <= 90)
{
result += str[i] + 32;
}
else
{
result += str[i];
}
}
return result;
}
std::vector<std::string> StringManip::Split(std::string str, char delim, int maxSplits) std::vector<std::string> StringManip::Split(std::string str, char delim, int maxSplits)
{ {
std::vector<std::string> splits; std::vector<std::string> splits;
@ -97,9 +134,12 @@ namespace jpUtils
std::string StringManip::GetFileNameFromPath(std::string path, bool includeExt) std::string StringManip::GetFileNameFromPath(std::string path, bool includeExt)
{ {
path.erase(path.begin(), std::find_if(path.rbegin(), path.rend(), [](int ch) { return ch == '\\' || ch == '/'; }).base()); if (path.find("\\") != std::string::npos || path.find("/") != std::string::npos)
{
path.erase(path.begin(), std::find_if(path.rbegin(), path.rend(), [](int ch) { return ch == '\\' || ch == '/'; }).base());
}
if (!includeExt) if (!includeExt && path.find(".") != std::string::npos)
{ {
path.erase(std::find_if(path.rbegin(), path.rend(), [](int ch) { return ch == '.'; }).base(), path.end()); path.erase(std::find_if(path.rbegin(), path.rend(), [](int ch) { return ch == '.'; }).base(), path.end());
path.erase(path.begin() + path.size() - 1); path.erase(path.begin() + path.size() - 1);

@ -22,6 +22,8 @@ namespace jpUtils
// Generic string helpers // Generic string helpers
// =========================================================== // ===========================================================
static std::string ToUpper(std::string str);
static std::string ToLower(std::string str);
// Splits the string based on the given delimiter, // Splits the string based on the given delimiter,
// maxSplit = -1 for unlimited number of splits // maxSplit = -1 for unlimited number of splits

Loading…
Cancel
Save