aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2017-12-13 18:35:52 +0100
committerdec05eba <dec05eba@protonmail.com>2017-12-13 18:37:07 +0100
commit92f24893a5e2d12d0c32662483117c7032623bf1 (patch)
tree2fac67d414383465f1257a875d7a23ab3cfd9814 /src
parentf2c70dfaba8d6481e86646080c51b6874d95f14e (diff)
Fix linking issue (linking in wrong order)
Change program argument handling. Add new program argument "new" to create a new sibs project which creates a project with all necessary files and also uses git init (ignores failure, for example if git is not installed). Change build path from "build" to "sibs-build" to prevent name clashing since "build" is a common name for directories.
Diffstat (limited to 'src')
-rw-r--r--src/Conf.cpp8
-rw-r--r--src/FileUtil.cpp1
-rw-r--r--src/GlobalLib.cpp17
-rw-r--r--src/main.cpp268
4 files changed, 208 insertions, 86 deletions
diff --git a/src/Conf.cpp b/src/Conf.cpp
index 8dd7608..1f439cd 100644
--- a/src/Conf.cpp
+++ b/src/Conf.cpp
@@ -378,11 +378,15 @@ namespace sibs
const StringView &packageTypeStr = value.asSingle();
if(packageTypeStr.equals("executable"))
packageType = PackageType::EXECUTABLE;
+ else if(packageTypeStr.equals("static"))
+ packageType = PackageType::STATIC;
+ else if(packageTypeStr.equals("dynamic"))
+ packageType = PackageType::DYNAMIC;
else if(packageTypeStr.equals("library"))
packageType = PackageType::LIBRARY;
else
{
- string errMsg = "Expected package.type to be either 'executable' or 'library', was: ";
+ string errMsg = "Expected package.type to be either 'executable', 'static', 'dynamic' or 'library', was: ";
errMsg += string(packageTypeStr.data, packageTypeStr.size);
throw ParserException(errMsg);
}
@@ -409,7 +413,7 @@ namespace sibs
void SibsConfig::finished()
{
if((int)packageType == -1)
- throw ParserException("Missing required config package.type. Expected to be one either 'executable' or 'library'");
+ throw ParserException("Missing required config package.type. Expected to be one either 'executable', 'static', 'dynamic' or 'library'");
finishedProcessing = true;
}
} \ No newline at end of file
diff --git a/src/FileUtil.cpp b/src/FileUtil.cpp
index 9a15938..899a1af 100644
--- a/src/FileUtil.cpp
+++ b/src/FileUtil.cpp
@@ -125,6 +125,7 @@ namespace sibs
errMsg += strerror(error);
return Result<bool>::Err(errMsg);
}
+ setbuf(file, NULL);
fwrite(data.data, 1, data.size, file);
fclose(file);
return Result<bool>::Ok(true);
diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp
index 177f1b9..203cd0f 100644
--- a/src/GlobalLib.cpp
+++ b/src/GlobalLib.cpp
@@ -136,11 +136,19 @@ namespace sibs
if(ninja.getSourceFiles().empty())
{
- return Result<string>::Ok("");
+ return Result<string>::Ok("No source files in dependency (header only library?)");
}
else
{
- string debugBuildPath = packageDir + "/build/debug";
+ string debugBuildPath = packageDir + "/sibs-build/debug";
+ string staticLibPath = debugBuildPath;
+ staticLibPath += "/lib";
+ staticLibPath += name;
+ staticLibPath += ".a";
+ linkerFlagCallbackFunc(staticLibPath);
+
+ // TODO: Use different directories depending on the project type, but .o build files should be in the same directory
+ // no matter what project type, since they are used for executables, static/dynamic libraries
Result<bool> createBuildDirResult = createDirectoryRecursive(debugBuildPath.c_str());
if(createBuildDirResult.isErr())
return Result<string>::Err(createBuildDirResult);
@@ -153,11 +161,6 @@ namespace sibs
if (buildResult.isErr())
return Result<string>::Err(buildResult.getErrMsg());
- string staticLibPath = debugBuildPath;
- staticLibPath += "/lib";
- staticLibPath += name;
- staticLibPath += ".a";
- linkerFlagCallbackFunc(staticLibPath);
return Result<string>::Ok(staticLibPath);
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 5c25414..9d6c88e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,9 @@
#include <cstdio>
+#include <iostream>
+#include <unordered_set>
#include "../include/FileUtil.hpp"
#include "../include/Conf.hpp"
+#include "../include/Exec.hpp"
#include "../backend/ninja/Ninja.hpp"
using namespace std;
@@ -9,17 +12,33 @@ using namespace sibs;
// TODO: Fail if multiple versions of the same dependency is used
// as linking will fail because of multiple definitions of the same thing
-// TODO: Detect recursive dependencies and give error.
+// TODO: Detect circular dependencies
+
+// TODO: Prevent infinite recursion in source file searching when there are symlinks.
+// Either do not follow the symlinks or use a hash map with every searched directory
+// to only go inside a directory once
void usage()
{
- printf("usage: sibs COMMAND\n\n");
+ printf("Usage: sibs COMMAND\n\n");
printf("Simple Build System for Native Languages\n\n");
- printf("Options:\n");
- printf(" -p\t\tPath to project (directory that contains main project.conf file)\n");
- printf(" -h\t\tPrint this help menu\n\n");
printf("Commands:\n");
printf(" build\t\tBuild a project that contains a project.conf file\n");
+ printf(" new\t\tCreate a new project\n");
+ exit(1);
+}
+
+void usageNew()
+{
+ printf("Usage: sibs new <project_name> <--exec|--static|--dynamic>\n\n");
+ printf("Create a new sibs project\n\n");
+ printf("Options:\n");
+ printf(" project_name\t\tThe name of the project you want to create\n");
+ printf(" --exec\t\t\tProject compiles to an executable\n");
+ printf(" --static\t\t\tProject compiles to a static library\n");
+ printf(" --dynamic\t\t\tProject compiles to a dynamic library\n");
+ printf("Examples:\n");
+ printf(" sibs new hello_world --exec\n");
exit(1);
}
@@ -28,12 +47,14 @@ void validateDirectoryPath(const char *projectPath)
FileType projectPathFileType = getFileType(projectPath);
if(projectPathFileType == FileType::FILE_NOT_FOUND)
{
- perror(projectPath);
+ string errMsg = "Invalid project path: ";
+ errMsg += projectPath;
+ perror(errMsg.c_str());
exit(2);
}
else if(projectPathFileType == FileType::REGULAR)
{
- printf("Expected project path (%s) to be a directory, was a file", projectPath);
+ cerr <<"Expected project path (" << projectPath << ") to be a directory, was a file" << endl;
exit(3);
}
}
@@ -43,17 +64,19 @@ void validateFilePath(const char *projectConfPath)
FileType projectConfFileType = getFileType(projectConfPath);
if(projectConfFileType == FileType::FILE_NOT_FOUND)
{
- perror(projectConfPath);
+ string errMsg = "Invalid project.conf path: ";
+ errMsg += projectConfPath;
+ perror(errMsg.c_str());
exit(4);
}
else if(projectConfFileType == FileType::DIRECTORY)
{
- printf("Expected project path (%s) to be a file, was a directory", projectConfPath);
+ cerr << "Expected project path (" << projectConfPath << ") to be a file, was a directory" << endl;
exit(5);
}
}
-const char *sourceFileExtensions[] = { "cc", "cpp", "cxx" };
+const char *sourceFileExtensions[] = { "c", "cc", "cpp", "cxx" };
bool isSourceFile(tinydir_file *file)
{
if(!file->is_reg)
@@ -68,8 +91,20 @@ bool isSourceFile(tinydir_file *file)
return false;
}
-void build(string projectPath)
+int buildProject(int argc, const char **argv)
{
+ if(argc > 1)
+ {
+ cerr << "Expected 'build' command to only be followed by one argument which is the path to a directory that contains a project.conf file, ";
+ cerr << "or none; in which case build would use the working directory as target directory" << endl << endl;
+ usage();
+ }
+
+ // TODO: If argc == 0 and working directory does not contain project.conf, then search every parent directory until one is found
+ string projectPath = ".";
+ if(argc == 1)
+ projectPath = argv[0];
+
validateDirectoryPath(projectPath.c_str());
if(projectPath.back() != '/')
projectPath += "/";
@@ -82,20 +117,36 @@ void build(string projectPath)
Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig);
if(result.isErr())
{
- printf("Failed to read config: %s\n", result.getErrMsg().c_str());
+ cerr << "Failed to read config: " << result.getErrMsg() << endl;
exit(6);
}
if(sibsConfig.getPackageName().empty())
{
- printf("project.conf is missing required field package.name\n");
+ cerr << "project.conf is missing required field package.name" << endl;
exit(10);
}
//string projectSrcPath = projectPath + "/src";
//validateDirectoryPath(projectSrcPath.c_str());
- backend::Ninja ninja;
+ PackageType packageType = sibsConfig.getPackageType();
+ backend::Ninja::LibraryType libraryType;
+ switch(packageType)
+ {
+ case PackageType::EXECUTABLE:
+ libraryType = backend::Ninja::LibraryType::EXECUTABLE;
+ break;
+ case PackageType::STATIC:
+ libraryType = backend::Ninja::LibraryType::STATIC;
+ break;
+ case PackageType::DYNAMIC:
+ case PackageType::LIBRARY:
+ libraryType = backend::Ninja::LibraryType::DYNAMIC;
+ break;
+ }
+
+ backend::Ninja ninja(libraryType);
walkDirFilesRecursive(projectPath.c_str(), [&ninja, &projectPath](tinydir_file *file)
{
if (isSourceFile(file))
@@ -108,11 +159,11 @@ void build(string projectPath)
}
});
- string debugBuildPath = projectPath + "/build/debug";
+ string debugBuildPath = projectPath + "/sibs-build/debug";
Result<bool> buildFileResult = ninja.createBuildFile(sibsConfig.getPackageName(), sibsConfig.getDependencies(), debugBuildPath.c_str());
if(buildFileResult.isErr())
{
- printf("Failed to build ninja file: %s\n", buildFileResult.getErrMsg().c_str());
+ cerr << "Failed to build ninja file: " << buildFileResult.getErrMsg() << endl;
exit(7);
}
@@ -121,81 +172,144 @@ void build(string projectPath)
{
exit(8);
}
+
+ return 0;
}
-int main(int argc, const char **argv)
+void newProjectCreateMainDir(const string &projectPath)
{
- string projectPath;
- string command;
- for(int i = 1; i < argc; ++i)
+ Result<bool> createProjectDirResult = createDirectoryRecursive(projectPath.c_str());
+ if(createProjectDirResult.isErr())
{
- const char *arg = argv[i];
- if(arg[0] == '-')
- {
- // Option
- if(strcmp(arg, "-p") == 0)
- {
- if(!projectPath.empty())
- {
- printf("-p option defined twice, should only be defined once\n");
- exit(1);
- }
-
- if(i < argc - 1)
- {
- projectPath = argv[i + 1];
- ++i;
- }
- else
- {
- printf("Expected project path after option -p\n");
- exit(1);
- }
- }
- else if(strcmp(arg, "-h") == 0)
- {
- usage();
- }
- else
- {
- printf("Invalid option %s, type sibs -h to see valid options\n", arg);
- exit(1);
- }
- }
- else
- {
- if(!command.empty())
- {
- printf("Found command twice. First as %s, then as %s\n", command.c_str(), arg);
- exit(1);
- }
- command = arg;
- }
+ cerr << "Failed to create project main directory: " << createProjectDirResult.getErrMsg() << endl;
+ exit(20);
}
+}
- if(projectPath.empty())
+void createProjectSubDir(const string &dir)
+{
+ Result<bool> createProjectDirResult = createDirectoryRecursive(dir.c_str());
+ if(createProjectDirResult.isErr())
{
- Result<string> projectPathResult = getCwd();
- if(projectPathResult.isErr())
- {
- printf("%s\n", projectPathResult.getErrMsg().c_str());
- exit(11);
- }
- projectPath = projectPathResult.unwrap();
+ cerr << "Failed to create directory in project: " << createProjectDirResult.getErrMsg() << endl;
+ exit(20);
}
+}
- if(command == "build")
- build(projectPath);
- else if(command.empty())
+void createProjectFile(const string &projectFilePath, const string &fileContent)
+{
+ Result<bool> fileOverwriteResult = fileOverwrite(projectFilePath.c_str(), fileContent.c_str());
+ if(fileOverwriteResult.isErr())
{
- printf("No command provided, type sibs -h to see valid commands\n");
- exit(1);
+ cerr << "Failed to create project file: " << fileOverwriteResult.getErrMsg() << endl;
+ exit(20);
}
+}
+
+void newProjectCreateConf(const string &projectName, const string &projectType, const string &projectPath)
+{
+ string projectConfStr = "[package]\n";
+ projectConfStr += "name = \"" + projectName + "\"\n";
+ projectConfStr += "type = \"" + projectType + "\"\n";
+ projectConfStr += "version = \"0.1.0\"\n\n";
+ projectConfStr += "[dependencies]\n";
+
+ string projectConfPath = projectPath;
+ projectConfPath += "/project.conf";
+ Result<bool> fileOverwriteResult = fileOverwrite(projectConfPath.c_str(), projectConfStr.c_str());
+ if(fileOverwriteResult.isErr())
+ {
+ cerr << "Failed to create project.conf: " << fileOverwriteResult.getErrMsg() << endl;
+ exit(20);
+ }
+}
+
+// This can be replaced with createDirectory and fileOverwrite, but it's not important
+// so there is no reason to do it (right now)
+Result<ExecResult> gitInitProject(const string &projectPath)
+{
+ string cmd = "git init '";
+ cmd += projectPath;
+ cmd += "'";
+ return exec(cmd.c_str());
+}
+
+int newProject(int argc, const char **argv)
+{
+ if(argc != 2)
+ {
+ cerr << "Expected 'new' command to be followed by two arguments - project name and type of project (--exec, --static or --dynamic)" << endl << endl;
+ usageNew();
+ }
+
+ Result<string> cwdResult = getCwd();
+ if(cwdResult.isErr())
+ {
+ cerr << "Failed to get current working directory: " << cwdResult.getErrMsg() << endl;
+ exit(20);
+ }
+
+ string projectName = argv[0];
+ string projectPath = cwdResult.unwrap();
+ projectPath += "/";
+ projectPath += projectName;
+ bool projectPathExists = getFileType(projectPath.c_str()) != FileType::FILE_NOT_FOUND;
+ if(projectPathExists)
+ {
+ cerr << "Unable to create a new project at path '" << projectPath << "'. A file or directory already exists in the same location" << endl;
+ exit(20);
+ }
+
+ const char *projectType = argv[1];
+
+ string projectTypeConf;
+ if(strcmp(projectType, "--exec") == 0)
+ projectTypeConf = "executable";
+ else if(strcmp(projectType, "--static") == 0)
+ projectTypeConf = "static";
+ else if(strcmp(projectType, "--dynamic") == 0)
+ projectTypeConf = "dynamic";
else
{
- printf("Invalid command %s, expected: build\n", command.c_str());
- exit(1);
+ cerr << "Expected project type to be either --exec, --static or --dynamic; was: " << projectType << endl << endl;
+ usageNew();
+ }
+
+ newProjectCreateMainDir(projectPath);
+ newProjectCreateConf(projectName, projectTypeConf, projectPath);
+ createProjectSubDir(projectPath + "/src");
+ createProjectSubDir(projectPath + "/include");
+ createProjectFile(projectPath + "/src/main.cpp", "#include <cstdio>\n\nint main()\n{ return 0;\n}\n");
+ // We are ignoring git init result on purpose. If it fails, just ignore it; not important
+ gitInitProject(projectPath);
+ return 0;
+}
+
+int main(int argc, const char **argv)
+{
+ unordered_map<string, string> param;
+ unordered_set<string> flags;
+
+ for(int i = 1; i < argc; ++i)
+ {
+ const char *arg = argv[i];
+ int subCommandArgCount = argc - i - 1;
+ const char **subCommandArgPtr = argv + i + 1;
+ if(strcmp(arg, "build") == 0)
+ {
+ return buildProject(subCommandArgCount, subCommandArgPtr);
+ }
+ else if(strcmp(arg, "new") == 0)
+ {
+ return newProject(subCommandArgCount, subCommandArgPtr);
+ }
+ else
+ {
+ cerr << "Expected command to be either 'build' or 'new', was: " << arg << endl << endl;
+ usage();
+ }
}
+ usage();
return 0;
}