Adds support for multiple libraries and submodules

Adds support for visual studio 17 and 22
Adds ability to remove the top-level project executable
master
Joey Pollack 4 years ago
parent 87ab9d48b8
commit ceadcc1802

@ -9,5 +9,6 @@ IF not exist build/ (
echo Removing the build directory
del /s /q build
rd /s /q build
mkdir build
:END

@ -4,4 +4,4 @@ REM ex. scripts/cmconfig.bat
@echo off
cmake -Wno-dev -B build/ -S . -G "Visual Studio 16 2019" -A x64
cmake -Wno-dev -B build/ -S . -G "Visual Studio 17 2022" -A x64

@ -17,6 +17,11 @@
#include <fstream>
#include <ctime>
int GenerateLibCMakeFile(std::string name, std::filesystem::path location);
int GenerateSubmodCMakeFile(std::string name, std::filesystem::path location, std::vector<std::string>& libraries);
int GenerateMainFile(std::string project_name, std::string mod_name, std::filesystem::path location);
void CleanUp(std::filesystem::path root);
typedef jpUtils::CmdArgParser::ArgDesc ArgDesc;
int main(int argc, char** argv)
@ -35,6 +40,10 @@ int main(int argc, char** argv)
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"));
argParser.AddArg(ArgDesc("-s", true, 1, "Specify the visual studio version to use (17, 19, 22). Default is 19"));
argParser.AddArg(ArgDesc("-a", true, 1, "Add library projects, separated by ',' (ex: -a first,second,third)"));
argParser.AddArg(ArgDesc("-x", true, 1, "Add executable submodule projects, separated by ',' (ex: -x first,second,third)"));
argParser.AddArg(ArgDesc("-r", true, 0, "Remove the root project executable"));
bool result = argParser.Parse();
@ -52,6 +61,62 @@ int main(int argc, char** argv)
return 1;
}
}
////////////////////////////////////////////////////////////
// Parse the submodules/libraries
////////////////////////////////////////////////////////////
// Libraries
std::vector<std::string> libraries;
if (argParser.ContainsOption("-a"))
{
std::string list = argParser.GetOptionValue("-a").values[0];
std::string current_name;
for (int i = 0; i < list.size(); i++)
{
if (list[i] == ',')
{
libraries.push_back(current_name);
current_name.clear();
}
else if (i + 1 == list.size())
{
current_name += list[i];
libraries.push_back(current_name);
current_name.clear();
}
else
{
current_name += list[i];
}
}
}
// Submodules
std::vector<std::string> submods;
if (argParser.ContainsOption("-x"))
{
std::string list = argParser.GetOptionValue("-x").values[0];
std::string current_name;
for (int i = 0; i < list.size(); i++)
{
if (list[i] == ',')
{
submods.push_back(current_name);
current_name.clear();
}
else if (i + 1 == list.size())
{
current_name += list[i];
submods.push_back(current_name);
current_name.clear();
}
else
{
current_name += list[i];
}
}
}
////////////////////////////////////////////////////////////
// Generate directory structure
@ -92,6 +157,37 @@ int main(int argc, char** argv)
return 1;
}
// Generate folders/files for any submodules/libraries
std::filesystem::path src = root / "src";
for (int i = 0; i < libraries.size(); i++)
{
std::filesystem::path location = src / libraries[i];
if (!std::filesystem::create_directory(location))
{
std::cout << "\nCould not create library directory: " << location.c_str();
return 1;
}
if (GenerateLibCMakeFile(libraries[i], location) > 0)
return 1;
}
src = root / "src";
for (int i = 0; i < submods.size(); i++)
{
std::filesystem::path location = src / submods[i];
if (!std::filesystem::create_directory(location))
{
std::cout << "\nCould not create submodule directory: " << location.c_str();
return 1;
}
if (GenerateSubmodCMakeFile(submods[i], location, libraries) > 0)
return 1;
}
////////////////////////////////////////////////////////////
// Generate CMake files
////////////////////////////////////////////////////////////
@ -127,20 +223,56 @@ int main(int argc, char** argv)
ofs << "\nset(CMAKE_CXX_STANDARD " << cversion << ")";
ofs << "\nset(CMAKE_CXX_STANDARD_REQUIRED True)";
ofs << "\n# setup target output directories";
ofs << "\nset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)";
ofs << "\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)";
ofs << "\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)";
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)";
// remove root executable if the option is set
if (!argParser.ContainsOption("-r"))
{
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\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 << "\n\ntarget_include_directories(${PROJECT_NAME}";
ofs << "\n\tPUBLIC \"${PROJECT_BINARY_DIR}\"";
ofs << "\n\tPUBLIC src";
ofs << "\n)";
// Link to any libs that exist
ofs << "\n\ntarget_link_directories(${PROJECT_NAME} ";
for (int i = 0; i < libraries.size(); i++)
{
ofs << "\n\tPRIVATE ../" << libraries[i].c_str();
}
ofs << ")";
ofs << "\n\ntarget_link_libraries(${PROJECT_NAME}";
for (int i = 0; i < libraries.size(); i++)
{
ofs << " " << libraries[i].c_str();
}
ofs << ")";
}
// include the libraries and submodules
for (int i = 0; i < libraries.size(); i++)
{
ofs << "\nadd_subdirectory(src/" << libraries[i].c_str() << ")";
}
for (int i = 0; i < submods.size(); i++)
{
ofs << "\nadd_subdirectory(src/" << submods[i].c_str() << ")";
}
ofs.close();
ofs.clear();
@ -284,6 +416,16 @@ int main(int argc, char** argv)
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::string vs_version = "\"Visual Studio 16 2019\"";
if (argParser.ContainsOption("-s"))
{
if (argParser.GetOptionValue("-s").values[0] == "17")
vs_version = "\"Visual Studio 15 2017\"";
if (argParser.GetOptionValue("-s").values[0] == "22")
vs_version = "\"Visual Studio 17 2022\"";
}
std::filesystem::path script_dir = root / "scripts";
if (gen_windows)
@ -303,7 +445,7 @@ int main(int argc, char** argv)
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 << "\n\ncmake -Wno-dev -B build/ -S . -G " << vs_version.c_str() << " -A x64";
ofs.close();
ofs.clear();
@ -353,6 +495,7 @@ int main(int argc, char** argv)
ofs << "\n\necho Removing the build directory";
ofs << "\ndel /s /q build";
ofs << "\nrd /s /q build";
ofs << "\nmkdir build";
ofs << "\n\n:END";
ofs.close();
ofs.clear();
@ -374,7 +517,7 @@ int main(int argc, char** argv)
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 << "\n\ncmake -S . -B build/";
ofs.close();
ofs.clear();
@ -392,36 +535,155 @@ int main(int argc, char** argv)
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 << "\n\ncmake -C build/";
ofs.close();
ofs.clear();
}
////////////////////////////////////////////////////////////
// Generate Main.cpp
// Generate Main.cpp files
////////////////////////////////////////////////////////////
std::filesystem::path main_file = root / "src/main.cpp";
ofs = std::ofstream(main_file.string().c_str());
// Check if there is a root project executable
if (!argParser.ContainsOption("-r"))
{
if (GenerateMainFile(project_name, project_name, root / "src/main.cpp") > 0)
return 1;
}
// Generate Main files for all libraries/submodules
for (int i = 0; i < libraries.size(); i++)
{
std::filesystem::path location = root / "src";
location /= libraries[i];
if (GenerateMainFile(project_name, libraries[i], location / "main.cpp") > 0)
return 1;
}
// Generate Main files for all libraries/submodules
for (int i = 0; i < submods.size(); i++)
{
std::filesystem::path location = root / "src";
location /= submods[i];
if (GenerateMainFile(project_name, submods[i], location / "main.cpp") > 0)
return 1;
}
std::cout << "\n\nNew project generated!";
return 0;
}
int GenerateLibCMakeFile(std::string name, std::filesystem::path location)
{
std::filesystem::path cmake_file = location / 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();
ofs << "\n\nset(MODULE_NAME " << name << ")";
ofs << "\n# specify the libraries source files";
ofs << "\nset( " << name << "_SRC";
ofs << "\n\tmain.cpp";
ofs << "\n)";
ofs << "\n\n# add the library";
ofs << "\nadd_library(${MODULE_NAME} ${" << name << "_SRC})";
ofs << "\n\ntarget_include_directories(${MODULE_NAME}";
ofs << "\n\tPUBLIC \"${PROJECT_BINARY_DIR}\"";
ofs << "\n)";
ofs.close();
ofs.clear();
return 0;
}
int GenerateSubmodCMakeFile(std::string name, std::filesystem::path location, std::vector<std::string>& libraries)
{
std::filesystem::path cmake_file = location / 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();
ofs << "\n\nset(MODULE_NAME " << name << ")";
ofs << "\n# specify the libraries source files";
ofs << "\nset( " << name << "_SRC";
ofs << "\n\tmain.cpp";
ofs << "\n)";
ofs << "\n\n# add the executable";
ofs << "\nadd_executable(${MODULE_NAME} ${" << name << "_SRC})";
ofs << "\n\ntarget_include_directories(${MODULE_NAME}";
ofs << "\n\tPUBLIC \"${PROJECT_BINARY_DIR}\"";
for (int i = 0; i < libraries.size(); i++)
{
ofs << "\n\tPUBLIC ../" << libraries[i].c_str();
}
ofs << "\n)";
// link to libs
ofs << "\n\ntarget_link_directories(${MODULE_NAME} ";
for (int i = 0; i < libraries.size(); i++)
{
ofs << "\n\tPRIVATE ../" << libraries[i].c_str();
}
ofs << "\n)";
ofs << "\n\ntarget_link_libraries(${MODULE_NAME}";
for (int i = 0; i < libraries.size(); i++)
{
ofs << " " << libraries[i].c_str();
}
ofs << ")";
ofs.close();
ofs.clear();
return 0;
}
int GenerateMainFile(std::string project_name, std::string mod_name, std::filesystem::path location)
{
std::ofstream ofs = std::ofstream(location.string().c_str());
if (!ofs.is_open())
{
std::cout << "\nCould not generate the config script file: " << main_file.string().c_str();
std::cout << "\nCould not generate the config script file: " << location.string().c_str();
return 1;
}
std::cout << "\nGenerating config script file: " << main_file.string().c_str();
std::cout << "\nGenerating main.cpp file: " << location.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 " << project_name << " version: \" << " << project_name << "_VERSION_MAJOR << \".\" << " << project_name << "_VERSION_MINOR << \".\" << " << project_name << "_VERSION_PATCH;";
ofs << "\n\tstd::cout << \"\\nThis is " << mod_name << " 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;
}
Loading…
Cancel
Save