Compare commits
10 Commits
5960af297c
...
c7a96b14e8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7a96b14e8 | ||
|
|
3cba603e7c | ||
|
|
abe970c173 | ||
|
|
5fd1f72624 | ||
|
|
fbb1868d82 | ||
|
|
1b889b7625 | ||
|
|
e61af99a0c | ||
|
|
38ca8ae719 | ||
|
|
b62d35a130 | ||
|
|
724b0047e6 |
19
README.md
19
README.md
@@ -1,5 +1,5 @@
|
|||||||
# ibuild
|
# ibuild
|
||||||
A simple build system written in C. The project is incomplete and is not meant to be used by anyone. It is designed to work out-of-the-box on C/C++ projects. However, it has a Recursive Descent Parser and supports a very small DSL. The DSL is in the format of a very basic configuration file. As of now, there is no complex configuration support as well as cross-platform compatibility features, as this is only available in linux.
|
A simple build system written in C. The project is incomplete and is not meant to be used by anyone. It is designed to work out-of-the-box on C/C++ projects.
|
||||||
|
|
||||||
## Security Disclaimer
|
## Security Disclaimer
|
||||||
The project has not been battle-tested yet. I am not using as a daily driver yet, and when I do, I will conduct thorough testing by fuzzing the application continously for a period of time (likely a week).
|
The project has not been battle-tested yet. I am not using as a daily driver yet, and when I do, I will conduct thorough testing by fuzzing the application continously for a period of time (likely a week).
|
||||||
@@ -12,13 +12,12 @@ You either place the executable to your /usr/local/bin, or place it into your pr
|
|||||||
Then run `ibuild`, and it should build the binary.
|
Then run `ibuild`, and it should build the binary.
|
||||||
|
|
||||||
## Configuration File
|
## Configuration File
|
||||||
Below is a sample configuration file;
|
Below is a sample (future) syntax;
|
||||||
````
|
````
|
||||||
COMPILER_PATH = "/usr/bin/gcc"
|
KEY = "VALUE";
|
||||||
SRC_DIR = "src" # Recursively discovers files here
|
KEY = ["VALUE1", "VALUE2"];
|
||||||
SRC_FILES = ["src/main.c"] # Manual file specification is optional
|
````
|
||||||
TARGET_EXEC = "ibuild" # executable name
|
### All Key-Values
|
||||||
DEP_SEARCHER = "/usr/bin/gcc" # Default, no need to specify explicitly
|
| Key | Value |
|
||||||
DEP_SEARCHER_FLAGS = "-MM" # Default, no need to specify explicitly
|
| --- | --- |
|
||||||
VERSION = "0.0.1" # Can specify version here, which would be passed as a macro.
|
| CC_COMPILER_PATH | `e.g. /usr/bin/gcc`|
|
||||||
````
|
|
||||||
2
build.sh
2
build.sh
@@ -1 +1 @@
|
|||||||
gcc -o ibuild src/main.c src/memory.c src/utils.c src/string.c src/discovery.c src/io.c -fsanitize=address -g -DDEBUG
|
gcc -o example/ibuild src/main.c src/memory.c src/utils.c src/string.c src/discovery.c src/io.c src/command.c src/build.c -fsanitize=address -g -DDEBUG -Wall -Wextra -Wpedantic -Wshadow
|
||||||
|
|||||||
8
example/main.c
Normal file
8
example/main.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("Hello world!\n");
|
||||||
|
printf("This is build 2!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
example/test.c
Normal file
1
example/test.c
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
87
src/build.c
Normal file
87
src/build.c
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "build.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "discovery.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
// Only supports C and multiple files
|
||||||
|
|
||||||
|
void build(BuildContext* bc)
|
||||||
|
{
|
||||||
|
assert(bc != NULL);
|
||||||
|
assert(bc->sp != NULL);
|
||||||
|
|
||||||
|
int sc = build_c_to_o(bc);
|
||||||
|
if(sc != 0) DIE("Compilation failed!");
|
||||||
|
link(bc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void link(BuildContext* bc)
|
||||||
|
{
|
||||||
|
assert(bc != NULL);
|
||||||
|
|
||||||
|
if(bc->obj_files == NULL) DIE("Linking process was triggered, however there are no object files.");
|
||||||
|
|
||||||
|
Command cmd;
|
||||||
|
cmd.a = bc->a;
|
||||||
|
cmd.app = bc->d->cc;
|
||||||
|
|
||||||
|
size_t len = bc->d->c_count + 2;
|
||||||
|
|
||||||
|
const char** args = (const char**)arena_alloc(bc->a, sizeof(const char*) * len);
|
||||||
|
|
||||||
|
args[0] = bc->d->cc.buf;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < bc->d->c_count; i++)
|
||||||
|
{
|
||||||
|
args[i + 1] = bc->obj_files[i]->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
args[len - 1] = NULL;
|
||||||
|
cmd.args = args;
|
||||||
|
|
||||||
|
int status = command_run(&cmd);
|
||||||
|
if(status != 0)
|
||||||
|
DIE("Linking failed with status code: %d");
|
||||||
|
|
||||||
|
LOG_DEBUG("Linking completed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
int build_c_to_o(BuildContext* bc)
|
||||||
|
{
|
||||||
|
assert(bc != NULL);
|
||||||
|
if(bc->d->c_count == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
CommandOptions co;
|
||||||
|
co.a = bc->a;
|
||||||
|
co.sp = bc->sp;
|
||||||
|
co.bp = bc->build_profile;
|
||||||
|
co.c = bc->c;
|
||||||
|
co.app = bc->d->cc;
|
||||||
|
|
||||||
|
StringView* arr = (StringView*)arena_alloc(bc->a, sizeof(StringView) * 1);
|
||||||
|
co.files = arr;
|
||||||
|
|
||||||
|
StringView** obj_files = (StringView**)arena_alloc(bc->a, sizeof(StringView*) * bc->d->c_count);
|
||||||
|
bc->obj_files = obj_files;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < bc->d->c_count; i++)
|
||||||
|
{
|
||||||
|
co.files[0] = bc->d->c_files[i]->path;
|
||||||
|
Command cmd = command_create_f_to_o(&co);
|
||||||
|
int status = command_run(&cmd);
|
||||||
|
if(status != 0)
|
||||||
|
DIE("Failed to compile %s, compiler exited with status code: %d", bc->d->c_files[i]->path.buf, status);
|
||||||
|
bc->obj_files[i] = &bc->d->c_files[i]->path;
|
||||||
|
LOG_DEBUG("Compiling %s", bc->d->c_files[i]->path.buf);
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
36
src/build.h
Normal file
36
src/build.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef BUILD_H
|
||||||
|
#define BUILD_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
typedef struct Configuration Configuration;
|
||||||
|
typedef struct Discovery Discovery;
|
||||||
|
typedef struct Arena Arena;
|
||||||
|
typedef struct StringPool StringPool;
|
||||||
|
typedef struct StringView StringView;
|
||||||
|
typedef struct Command Command;
|
||||||
|
|
||||||
|
struct BuildContext
|
||||||
|
{
|
||||||
|
// Memory
|
||||||
|
Arena* a;
|
||||||
|
StringPool* sp;
|
||||||
|
|
||||||
|
// Build Params
|
||||||
|
enum BuildProfile build_profile;
|
||||||
|
Configuration* c;
|
||||||
|
Discovery* d;
|
||||||
|
|
||||||
|
StringView** obj_files;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum BuildProfile BuildProfile;
|
||||||
|
typedef struct BuildContext BuildContext;
|
||||||
|
|
||||||
|
void build(BuildContext* bc);
|
||||||
|
|
||||||
|
void link(BuildContext* bc);
|
||||||
|
|
||||||
|
int build_c_to_o(BuildContext* bc);
|
||||||
|
|
||||||
|
#endif
|
||||||
87
src/command.c
Normal file
87
src/command.c
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
#include "discovery.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
// TODO: This file is UNSAFE. This file is purely here for MVP purposes, and to self-host this program itself.
|
||||||
|
|
||||||
|
Command command_create_f_to_o(CommandOptions* co)
|
||||||
|
{
|
||||||
|
assert(co != NULL);
|
||||||
|
|
||||||
|
size_t len_args = 6;
|
||||||
|
|
||||||
|
ProfileResult pr = command_get_profile(co);
|
||||||
|
len_args += pr.compiler_flags_count;
|
||||||
|
|
||||||
|
const char** args_buf = (const char**)arena_alloc(co->a, sizeof(const char*) * len_args);
|
||||||
|
args_buf[0] = co->app.buf;
|
||||||
|
args_buf[1] = "-c";
|
||||||
|
args_buf[2] = co->files[0].buf;
|
||||||
|
args_buf[3] = "-o";
|
||||||
|
|
||||||
|
StringView o_ext = STR_LIT(co->sp, ".o");
|
||||||
|
StringView f_o = string_concat_ss(co->sp, &co->files[0], &o_ext);
|
||||||
|
args_buf[4] = f_o.buf;
|
||||||
|
args_buf[5] = "-MMD";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pr.compiler_flags_count; i++)
|
||||||
|
{
|
||||||
|
args_buf[i + 5] = pr.compiler_flags_buf[i].buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
args_buf[len_args] = NULL;
|
||||||
|
|
||||||
|
LOG_DEBUG("Command created, first 4 args: %s %s %s %s %s | total args: %d", args_buf[0], args_buf[1], args_buf[2], args_buf[3], args_buf[4], len_args);
|
||||||
|
|
||||||
|
return (Command){.a = co->a, .app = co->app, .args = args_buf};
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfileResult command_get_profile(CommandOptions* co)
|
||||||
|
{
|
||||||
|
ProfileResult pr;
|
||||||
|
switch(co->bp)
|
||||||
|
{
|
||||||
|
case B_DEBUG:
|
||||||
|
pr.compiler_flags_count = co->c->debug_compiler_flags_c;
|
||||||
|
pr.compiler_flags_buf = co->c->debug_compiler_flags;
|
||||||
|
break;
|
||||||
|
case B_PROD:
|
||||||
|
pr.compiler_flags_count = co->c->prod_compiler_flags_c;
|
||||||
|
pr.compiler_flags_buf = co->c->prod_compiler_flags;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DIE("No configuration was selected!");
|
||||||
|
}
|
||||||
|
return pr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add input sanitization to cmd->app and cmd->args
|
||||||
|
int command_run(Command* cmd)
|
||||||
|
{
|
||||||
|
assert(cmd != NULL);
|
||||||
|
if(cmd->args == NULL) DIE("No arguments were supplied to the command");
|
||||||
|
|
||||||
|
pid_t pid = fork();
|
||||||
|
|
||||||
|
if(pid == -1) DIE("fork failed, could not create child process.");
|
||||||
|
|
||||||
|
if(pid == 0)
|
||||||
|
{
|
||||||
|
if(execvp(cmd->app.buf, (char*const*)cmd->args) == -1)
|
||||||
|
DIE("Failed to launch command: %s.", cmd->app.buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int wstatus = 0;
|
||||||
|
if(waitpid(pid, &wstatus, 0) == -1) DIE("wait failed.");
|
||||||
|
LOG_DEBUG("Command calling app %s exited with status code %d on child process PID %d.", cmd->app.buf, wstatus, pid);
|
||||||
|
return wstatus;
|
||||||
|
}
|
||||||
|
|
||||||
44
src/command.h
Normal file
44
src/command.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef COMMAND_H
|
||||||
|
#define COMMAND_H
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
typedef struct Arena Arena;
|
||||||
|
typedef struct Discovery Discovery;
|
||||||
|
typedef struct Configuration Configuration;
|
||||||
|
|
||||||
|
struct CommandOptions
|
||||||
|
{
|
||||||
|
Arena* a;
|
||||||
|
StringPool* sp;
|
||||||
|
BuildProfile bp;
|
||||||
|
Configuration* c;
|
||||||
|
StringView app;
|
||||||
|
StringView* files;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProfileResult
|
||||||
|
{
|
||||||
|
size_t compiler_flags_count;
|
||||||
|
StringView* compiler_flags_buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Command
|
||||||
|
{
|
||||||
|
Arena* a;
|
||||||
|
StringView app;
|
||||||
|
const char** args;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Argument Argument;
|
||||||
|
typedef struct Command Command;
|
||||||
|
typedef struct CommandOptions CommandOptions;
|
||||||
|
typedef struct ProfileResult ProfileResult;
|
||||||
|
|
||||||
|
Command command_create_f_to_o(CommandOptions* co);
|
||||||
|
ProfileResult command_get_profile(CommandOptions* co);
|
||||||
|
|
||||||
|
int command_run(Command* cmd);
|
||||||
|
|
||||||
|
#endif
|
||||||
12
src/common.h
Normal file
12
src/common.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
|
||||||
|
enum BuildProfile
|
||||||
|
{
|
||||||
|
B_DEBUG,
|
||||||
|
B_PROD
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum BuildProfile BuildProfile;
|
||||||
|
|
||||||
|
#endif
|
||||||
2
src/config.c
Normal file
2
src/config.c
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
30
src/config.h
Normal file
30
src/config.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
struct Configuration
|
||||||
|
{
|
||||||
|
// C-Compiler Flags
|
||||||
|
StringView cc_compiler_path;
|
||||||
|
StringView src_dir;
|
||||||
|
|
||||||
|
// General Flags
|
||||||
|
//StringView* src_files;
|
||||||
|
|
||||||
|
// Debug Profile
|
||||||
|
StringView* debug_compiler_flags;
|
||||||
|
size_t debug_compiler_flags_c;
|
||||||
|
|
||||||
|
// Production Profile
|
||||||
|
StringView* prod_compiler_flags;
|
||||||
|
size_t prod_compiler_flags_c;
|
||||||
|
|
||||||
|
// Linker arguments
|
||||||
|
StringView* linker_flags;
|
||||||
|
size_t linker_flags_c;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Configuration Configuration;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,6 +7,9 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
Discovery discovery_create(Arena* a, StringPool* sp)
|
Discovery discovery_create(Arena* a, StringPool* sp)
|
||||||
{
|
{
|
||||||
@@ -31,23 +34,18 @@ Discovery discovery_create(Arena* a, StringPool* sp)
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void discovery_cleanup(Discovery* d)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void discovery_discover(Discovery* d)
|
void discovery_discover(Discovery* d)
|
||||||
{
|
{
|
||||||
assert(d != NULL);
|
assert(d != NULL);
|
||||||
DirOpContext doc;
|
DirOpContext doc;
|
||||||
doc.a_f = d->a;
|
doc.a_f = d->a;
|
||||||
doc.sp = d->sp;
|
doc.sp = d->sp;
|
||||||
StringView path = SV(d->sp, ".");
|
StringView path = STR_LIT(d->sp, ".");
|
||||||
size_t count = dir_get_recursive(&doc, &path);
|
size_t count = dir_get_recursive(&doc, &path);
|
||||||
d->file_count = count;
|
d->file_count = count;
|
||||||
LOG_DEBUG("Discovered %d files.", count);
|
LOG_DEBUG("Discovered %d files.", count);
|
||||||
|
|
||||||
StringView c_ext = SV(d->sp, ".c");
|
StringView c_ext = STR_LIT(d->sp, ".c");
|
||||||
ExtDiscoveryResult c_res = discovery_discover_ext(d, d->a, &c_ext);
|
ExtDiscoveryResult c_res = discovery_discover_ext(d, d->a, &c_ext);
|
||||||
|
|
||||||
if(c_res.mem != NULL)
|
if(c_res.mem != NULL)
|
||||||
@@ -57,7 +55,7 @@ void discovery_discover(Discovery* d)
|
|||||||
d->c_files = c_res.mem;
|
d->c_files = c_res.mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringView h_ext = SV(d->sp, ".h");
|
StringView h_ext = STR_LIT(d->sp, ".h");
|
||||||
ExtDiscoveryResult h_res = discovery_discover_ext(d, d->a, &h_ext);
|
ExtDiscoveryResult h_res = discovery_discover_ext(d, d->a, &h_ext);
|
||||||
|
|
||||||
if(h_res.mem != NULL)
|
if(h_res.mem != NULL)
|
||||||
@@ -66,6 +64,35 @@ void discovery_discover(Discovery* d)
|
|||||||
d->h_count = h_res.len;
|
d->h_count = h_res.len;
|
||||||
d->h_files = h_res.mem;
|
d->h_files = h_res.mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(d->c_count > 0)
|
||||||
|
{
|
||||||
|
discovery_discover_ccompiler(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void discovery_discover_ccompiler(Discovery* d)
|
||||||
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
|
StringView gcc = STR_LIT(d->sp, "gcc");
|
||||||
|
StringView cc_gcc = discovery_discover_path(d, &gcc);
|
||||||
|
|
||||||
|
if(cc_gcc.buf != NULL)
|
||||||
|
{
|
||||||
|
d->cc = cc_gcc;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView clang = STR_LIT(d->sp, "clang");
|
||||||
|
StringView cc_clang = discovery_discover_path(d, &clang);
|
||||||
|
|
||||||
|
if(cc_clang.buf != NULL)
|
||||||
|
{
|
||||||
|
d->cc = cc_clang;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG_DEBUG("No C compilers were found, however, %d C files were found. Not installed?", d->c_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make the search logic faster, or at least search all of the wanted extension at once, uniformly.
|
// TODO: Make the search logic faster, or at least search all of the wanted extension at once, uniformly.
|
||||||
@@ -91,9 +118,40 @@ ExtDiscoveryResult discovery_discover_ext(Discovery* d, Arena* a, StringView* ex
|
|||||||
DirEntry** entry = (DirEntry**)arena_alloc(a, sizeof(DirEntry*));
|
DirEntry** entry = (DirEntry**)arena_alloc(a, sizeof(DirEntry*));
|
||||||
*entry = &d->files[i];
|
*entry = &d->files[i];
|
||||||
count++;
|
count++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count > 0) return (ExtDiscoveryResult){.mem = res, .len = count};
|
if(count > 0) return (ExtDiscoveryResult){.mem = res, .len = count};
|
||||||
return (ExtDiscoveryResult){.mem = NULL, .len = 0};
|
return (ExtDiscoveryResult){.mem = NULL, .len = 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringView discovery_discover_path(Discovery* d, StringView* s)
|
||||||
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
char* path_env = getenv("PATH");
|
||||||
|
|
||||||
|
if(path_env == NULL) return (StringView){.buf = NULL, .len = 0};
|
||||||
|
|
||||||
|
char* path = strdup(path_env);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if(path == NULL && errno != 0) DIE("String copy failure.");
|
||||||
|
|
||||||
|
char* current = strtok(path, ":");
|
||||||
|
do
|
||||||
|
{
|
||||||
|
LOG_DEBUG("Checking: %s for %s in PATH.", current, s->buf);
|
||||||
|
StringView p = string_create(d->sp, current, strlen(current));
|
||||||
|
StringView fp = path_concat_ss(d->sp, &p, s);
|
||||||
|
if(access(fp.buf, X_OK) == 0)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("Found %s in PATH:%s", s->buf, p.buf);
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
}while((current = strtok(NULL, ":")) != NULL);
|
||||||
|
|
||||||
|
return (StringView){.buf = NULL, .len = 0};
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
typedef struct Arena Arena;
|
typedef struct Arena Arena;
|
||||||
typedef struct StringPool StringPool;
|
typedef struct StringPool StringPool;
|
||||||
typedef struct StringView StringView;
|
|
||||||
typedef struct DirEntry DirEntry;
|
typedef struct DirEntry DirEntry;
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
struct Discovery
|
struct Discovery
|
||||||
{
|
{
|
||||||
// Memory
|
// Memory
|
||||||
@@ -25,6 +26,9 @@ struct Discovery
|
|||||||
size_t c_count;
|
size_t c_count;
|
||||||
size_t h_count;
|
size_t h_count;
|
||||||
size_t cpp_count;
|
size_t cpp_count;
|
||||||
|
|
||||||
|
StringView cc;
|
||||||
|
StringView cxx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExtDiscoveryResult
|
struct ExtDiscoveryResult
|
||||||
@@ -40,6 +44,9 @@ Discovery discovery_create(Arena* a, StringPool* sp);
|
|||||||
void discovery_cleanup(Discovery* d);
|
void discovery_cleanup(Discovery* d);
|
||||||
void discovery_discover(Discovery* d);
|
void discovery_discover(Discovery* d);
|
||||||
|
|
||||||
|
void discovery_discover_ccompiler(Discovery* d);
|
||||||
|
|
||||||
ExtDiscoveryResult discovery_discover_ext(Discovery* d, Arena* a, StringView* ext);
|
ExtDiscoveryResult discovery_discover_ext(Discovery* d, Arena* a, StringView* ext);
|
||||||
|
StringView discovery_discover_path(Discovery* d, StringView* s);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
8
src/io.c
8
src/io.c
@@ -14,10 +14,10 @@ StringView path_concat_ss(StringPool *sp, StringView* a, StringView* b)
|
|||||||
if(b == NULL) DIE("b must be a valid string!");
|
if(b == NULL) DIE("b must be a valid string!");
|
||||||
if(a->len <= 0 || b->len <= 0) DIE("a and b must not be empty! (a:%d, b:%d)", a->len, b->len);
|
if(a->len <= 0 || b->len <= 0) DIE("a and b must not be empty! (a:%d, b:%d)", a->len, b->len);
|
||||||
if(a->buf[a->len - 1] == '/')
|
if(a->buf[a->len - 1] == '/')
|
||||||
return string_createcat_ss(sp, a, b);
|
return string_concat_ss(sp, a, b);
|
||||||
StringView slash = (StringView){.buf = "/", .len = 1};
|
StringView slash = (StringView){.buf = "/", .len = 1};
|
||||||
StringView ts = string_createcat_ss(sp, a, &slash);
|
StringView ts = string_concat_ss(sp, a, &slash);
|
||||||
return string_createcat_ss(sp, &ts, b);
|
return string_concat_ss(sp, &ts, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utilize DFS for recursive directory search.
|
// Utilize DFS for recursive directory search.
|
||||||
@@ -40,7 +40,7 @@ size_t dir_get_recursive(DirOpContext* doc, StringView* p)
|
|||||||
if(de == NULL && errno != 0) DIE("failed to read directory: \"%s\"", p);
|
if(de == NULL && errno != 0) DIE("failed to read directory: \"%s\"", p);
|
||||||
if(de == NULL) break;
|
if(de == NULL) break;
|
||||||
|
|
||||||
if(de->d_type == DT_UNKNOWN) DIE("Filesystem not supported!!");
|
if(de->d_type == DT_UNKNOWN) DIE("Filesystem not supported!!"); // Add support for modern filesystems using stat()
|
||||||
if(de->d_type != DT_DIR && de->d_type != DT_REG) continue;
|
if(de->d_type != DT_DIR && de->d_type != DT_REG) continue;
|
||||||
if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0 || strcmp(de->d_name, ".git") == 0) continue;
|
if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0 || strcmp(de->d_name, ".git") == 0) continue;
|
||||||
|
|
||||||
|
|||||||
28
src/main.c
28
src/main.c
@@ -7,20 +7,36 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "discovery.h"
|
#include "discovery.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "build.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void)
|
||||||
Backend b = {NULL, 0};
|
{
|
||||||
|
Backend b = BACKEND_CONST;
|
||||||
backend_initialize(&b);
|
backend_initialize(&b);
|
||||||
|
|
||||||
Arena a_sp = arena_create(&b, MEM_ARENA_MAX_CAP);
|
Arena a_sp = arena_create(&b, MEM_ARENA_MAX_CAP);
|
||||||
StringPool sp = string_pool_create(&a_sp);
|
StringPool sp = string_pool_create(&a_sp);
|
||||||
|
|
||||||
Arena a_sptemp = arena_create(&b, MEM_ARENA_MAX_CAP);
|
|
||||||
StringPool sp_temp = string_pool_create(&a_sptemp);
|
|
||||||
|
|
||||||
Arena a_d = arena_create(&b, 1024*1024*5); // 5MB for Discovery
|
Arena a_d = arena_create(&b, 1024*1024*5); // 5MB for Discovery
|
||||||
Discovery d = discovery_create(&a_d, &sp);
|
Discovery d = discovery_create(&a_d, &sp);
|
||||||
discovery_discover(&d);
|
discovery_discover(&d);
|
||||||
|
|
||||||
|
Configuration sample_config;
|
||||||
|
/* Command cmd = command_create(&a_cmd, &d, &sample_config); */
|
||||||
|
/* command_run(&cmd); */
|
||||||
|
|
||||||
|
Arena a_b = arena_create(&b, 1024*1024*5);
|
||||||
|
|
||||||
|
BuildContext bc;
|
||||||
|
bc.build_profile = B_DEBUG;
|
||||||
|
bc.d = &d;
|
||||||
|
bc.c = &sample_config;
|
||||||
|
bc.a = &a_b;
|
||||||
|
bc.sp = &sp;
|
||||||
|
|
||||||
|
build(&bc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#ifndef MEMORY_H
|
#ifndef MEMORY_H
|
||||||
#define MEMORY_H
|
#define MEMORY_H
|
||||||
|
|
||||||
|
|
||||||
#ifndef MEM_ARENA_MAX_CAP
|
#ifndef MEM_ARENA_MAX_CAP
|
||||||
#define MEM_ARENA_MAX_CAP 1024 * 1024
|
#define MEM_ARENA_MAX_CAP 1024 * 1024
|
||||||
#endif
|
#endif
|
||||||
@@ -20,16 +19,20 @@ struct Backend
|
|||||||
size_t cap;
|
size_t cap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BACKEND_CONST {NULL, NULL, 0, 0}
|
||||||
|
|
||||||
struct Arena
|
struct Arena
|
||||||
{
|
{
|
||||||
void* mem;
|
void* mem;
|
||||||
void* last;
|
void* last;
|
||||||
size_t len;
|
size_t len;
|
||||||
size_t cap;
|
size_t cap;
|
||||||
void* next;
|
void* next; //TODO
|
||||||
struct Backend* b;
|
struct Backend* b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ARENA_CONST {NULL, NULL, 0, 0, NULL}
|
||||||
|
|
||||||
typedef struct Backend Backend;
|
typedef struct Backend Backend;
|
||||||
typedef struct Arena Arena;
|
typedef struct Arena Arena;
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,6 @@ StringPool string_pool_create(Arena* a)
|
|||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_pool_reset(StringPool* ps)
|
|
||||||
{
|
|
||||||
// arena_reset(&ps->a);
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView string_create(StringPool* sp, const char* s, size_t len)
|
StringView string_create(StringPool* sp, const char* s, size_t len)
|
||||||
{
|
{
|
||||||
assert(sp != NULL);
|
assert(sp != NULL);
|
||||||
@@ -30,7 +25,7 @@ StringView string_create(StringPool* sp, const char* s, size_t len)
|
|||||||
return (StringView){.buf = buf, .len=len};
|
return (StringView){.buf = buf, .len=len};
|
||||||
}
|
}
|
||||||
|
|
||||||
StringView string_createcat_ss(StringPool* sp, StringView* a, StringView* b)
|
StringView string_concat_ss(StringPool* sp, StringView* a, StringView* b)
|
||||||
{
|
{
|
||||||
if(a == NULL) DIE("a must be a valid C-style string!");
|
if(a == NULL) DIE("a must be a valid C-style string!");
|
||||||
if(b == NULL) DIE("b must be a valid C-style string!");
|
if(b == NULL) DIE("b must be a valid C-style string!");
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define SV(sp, s) string_create(sp, s, sizeof(s) - 1)
|
#define STR_LIT(sp, s) string_create(sp, s, sizeof(s) - 1)
|
||||||
|
|
||||||
struct StringPool
|
struct StringPool
|
||||||
{
|
{
|
||||||
@@ -22,11 +22,10 @@ typedef struct StringPool StringPool;
|
|||||||
typedef struct StringView StringView;
|
typedef struct StringView StringView;
|
||||||
|
|
||||||
StringPool string_pool_create(Arena* a);
|
StringPool string_pool_create(Arena* a);
|
||||||
void string_pool_reset(StringPool* sp);
|
|
||||||
|
|
||||||
StringView string_create(StringPool* sp, const char* s, size_t len);
|
StringView string_create(StringPool* sp, const char* s, size_t len);
|
||||||
|
|
||||||
// Ensure that lengths do not contain null term
|
// Ensure that lengths do not contain null term
|
||||||
StringView string_createcat_ss(StringPool* sp, StringView* a, StringView* b);
|
StringView string_concat_ss(StringPool* sp, StringView* a, StringView* b);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
void die_f(const char* func, int l, const char* fmt,...)
|
void die_f(const char* func, int l, const char* fmt,...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args);
|
va_start(args, fmt);
|
||||||
printf("IBUILD Error (%d:%s): ", l, func);
|
printf("IBUILD Error (%d:%s): ", l, func);
|
||||||
vprintf(fmt, args);
|
vprintf(fmt, args);
|
||||||
printf("\nlast syscall error: \n", strerror(errno));
|
printf("\nlast syscall error: %s \n", strerror(errno));
|
||||||
va_end(args);
|
va_end(args);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ void die_f(const char* func, int l, const char* fmt,...)
|
|||||||
void log_f(const char* func, int l, const char* fmt, ...)
|
void log_f(const char* func, int l, const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args);
|
va_start(args, fmt);
|
||||||
printf("IBUILD Log (%d:%s): ", l, func);
|
printf("IBUILD Log (%d:%s): ", l, func);
|
||||||
vprintf(fmt, args);
|
vprintf(fmt, args);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user