Skip to content

Commit

Permalink
added the ability to -w and rebuild on change
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan-J-D committed Dec 7, 2023
1 parent c774cb7 commit 3af19de
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 20 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ A tool to simplify CMake Toolchain Commands

### Usage:
```bash
Usage: cmakeauto help|build|configure|template -b <build path> -s <source path> [-g <Generator>] [-m <Mode>] [-a <Architecture>] [-ei <Extra Init Params>] [-eb <Extra Build Params>] [-ar] [-t <Template>]
makeauto help|build|configure|template -b <build path> -s <source path> [-g <Generator>] [-m <Mode>] [-a <Architecture>] [-ei <Extra Init Params>] [-eb <Extra Build Params>] [-w <Directories>] [-t <Template>]
help: print help message
build: build project
configure: configure project
Expand All @@ -21,11 +21,12 @@ Parameters:
x64: 64-bit
-ei: (Optional) This specifies extra init params to be passed to cmake.
-eb: (Optional) This specifies extra build params to be passed to cmake.
-ar: (Optional) This specifies whether to auto reload the project when source files changed.
-w: (Optional) This specifies the directories to be watched and will auto rebuild if a change was found.
-t: (Only for Template Action) This specifies the template to be used when creating a template project.

Templates:
helloworld
helloworlddll
```
### Build with CMake For Release X64:
Expand Down
200 changes: 190 additions & 10 deletions cmakeauto.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ bool cma_file_exists(const char *path)
#endif
}

bool cma_folder_exists(const char *path)
{
#ifdef _WIN32
DWORD attr = GetFileAttributesA(path);
return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
#elif __linux__
struct stat st = {0};
return stat(path, &st) != -1 && S_ISDIR(st.st_mode);
#else
#error unsupported platform
#endif
}

bool cma_copy_file(const char *src, const char *dst)
{
#ifdef _WIN32
Expand Down Expand Up @@ -252,22 +265,174 @@ bool cma_create_process(char *filename,
return true;
}

#ifdef __linux__
bool cma_watch_add_folder_callback(const char *abspath, // return false to stop iterating
const char *relpath,
const char *name,
bool isfolder /* 0 = file, 1 = folder */,
void *userdata)
{
CMakeAutoConfig *config = (CMakeAutoConfig *)userdata;
if (isfolder)
{
if (config->watchfolderhandles_count >= WATCHFOLDER_MAX_LEN)
{
printf("max watch folders reached\n");
return false;
}

config->watchfolderhandles[config->watchfolderhandles_count] =
inotify_add_watch(config->watchfolderhandles[0], abspath, IN_CREATE | IN_MODIFY | IN_DELETE);
config->watchfolderhandles_count++;
}

return true;
}

void cma_watch_remove_all_subfolders(CMakeAutoConfig *config)
{
for (unsigned int i = config->watchfolders_count + 1; i < config->watchfolderhandles_count; i++)
inotify_rm_watch(config->watchfolderhandles[0], config->watchfolderhandles[i]);
config->watchfolderhandles_count = config->watchfolders_count + 1;
}
#endif

bool cma_watch_folder_init(CMakeAutoConfig *config)
{
/* Unimplemented */
return false;
#ifdef _WIN32
config->watchfolderhandles_count = config->watchfolders_count;
config->watchfolderhandles = (watchfolderhandle_t *)malloc(sizeof(watchfolderhandle_t) * config->watchfolderhandles_count);
for (unsigned int i = 0; i < config->watchfolderhandles_count; i++)
{
config->watchfolderhandles[i] = FindFirstChangeNotificationA(config->watchfolders[i],
TRUE,
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME);
if (config->watchfolderhandles[i] == INVALID_HANDLE_VALUE)
{
printf("failed to watch folder %s\n", config->srcdir);
return false;
}
}

return true;
#elif __linux__
config->watchfolderhandles_count = config->watchfolders_count + 1;
config->watchfolderhandles = (watchfolderhandle_t *)malloc(sizeof(watchfolderhandle_t) * config->watchfolderhandles_count);
config->watchfolderhandles[0] = inotify_init();
if (config->watchfolderhandles[0] == -1)
{
printf("failed to watch folder %s\n", config->srcdir);
return false;
}

for (unsigned int i = 0; i < config->watchfolders_count; i++)
{
config->watchfolderhandles[i + 1] = inotify_add_watch(config->watchfolderhandles[0], config->watchfolders[i], IN_CREATE | IN_MODIFY | IN_DELETE);
if (config->watchfolderhandles[i + 1] < 0)
{
printf("failed to watch folder %s\n", config->srcdir);
return false;
}

cma_iterate_dir(config->watchfolders[i], ".", config, true, cma_watch_add_folder_callback);
}

return true;
#else
#error unsupported platform
#endif
}

bool cma_watch_folder_wait_for_next_change(CMakeAutoConfig *config)
{
/* Unimplemented */
return false;
#ifdef _WIN32
while (true)
{
unsigned long wait_result = WaitForMultipleObjects(config->watchfolderhandles_count, config->watchfolderhandles, FALSE, INFINITE);
if (wait_result == WAIT_FAILED)
{
printf("failed to wait for folder change\n");
return false;
}

if (wait_result == WAIT_TIMEOUT)
continue;

if (wait_result >= WAIT_OBJECT_0 && wait_result < WAIT_OBJECT_0 + config->watchfolderhandles_count)
{
if (FindNextChangeNotification(config->watchfolderhandles[wait_result - WAIT_OBJECT_0]) == FALSE)
{
printf("failed to watch folder %s\n", config->srcdir);
return false;
}
break;
}
}

return true;
#elif __linux__
while (true)
{
char buf[4096] ALIGNAS(struct inotify_event);
const struct inotify_event *event;
unsigned long long len;
char *ptr;

len = read(config->watchfolderhandles[0], buf, sizeof(buf));
if (len == -1 && errno != EAGAIN)
{
printf("failed to read inotify event\n");
return false;
}

if (len <= 0)
{
printf("inotify event len <= 0\n");
return false;
}

for (ptr = buf; ptr < buf + len; ptr += sizeof(struct inotify_event) + event->len)
{
event = (const struct inotify_event *)ptr;

if (event->mask & (IN_CREATE | IN_DELETE))
{
if (event->mask & IN_ISDIR)
{
cma_watch_remove_all_subfolders(config);

for (unsigned int i = 0; i < config->watchfolders_count; i++)
cma_iterate_dir(config->watchfolders[i], ".", config, true, cma_watch_add_folder_callback);
}
}
}

break;
}
return true;
#else
#error unsupported platform
#endif
}

bool cma_watch_folder_close(CMakeAutoConfig *config)
{
/* Unimplemented */
return false;
#ifdef _WIN32
for (unsigned int i = 0; i < config->watchfolderhandles_count; i++)
FindCloseChangeNotification(config->watchfolderhandles[i]);
return true;
#elif __linux__
printf("closing watch folder\n");
for (unsigned int i = 1; i < config->watchfolderhandles_count; i++)
inotify_rm_watch(config->watchfolderhandles[0], config->watchfolderhandles[i]);
close(config->watchfolderhandles[0]);
return true;
#else
#error unsupported platform
#endif
}

bool cma_init_proj(CMakeAutoConfig *config)
Expand Down Expand Up @@ -479,11 +644,26 @@ int main(int argc, char **argv)
{
case CMAKE_AUTO_ACTION_BUILD:
{
if (cma_init_proj(&config))
cma_build(&config);
if (config.options & CMAKE_AUTO_OPTION_AUTO_RELOAD)
if (!cma_watch_folder_init(&config))
{
printf("failed to init watch folder\n");
break;
}

do
{
if (cma_init_proj(&config))
cma_build(&config);

if (config.options & CMAKE_AUTO_OPTION_AUTO_RELOAD)
if (!cma_watch_folder_wait_for_next_change(&config))
printf("failed to wait for next change\n");
} while (config.options & CMAKE_AUTO_OPTION_AUTO_RELOAD);

if (config.options & CMAKE_AUTO_OPTION_AUTO_RELOAD)
printf("auto reload is not implemented yet\n");
if (!cma_watch_folder_close(&config))
printf("failed to close watch folder\n");
break;
}
case CMAKE_AUTO_ACTION_CONFIGURE:
Expand All @@ -500,7 +680,7 @@ int main(int argc, char **argv)
strcat_s(buf, FILE_MAX_PATH, "templates" FILE_SEPERATOR);
strcat_s(buf, FILE_MAX_PATH, config.template);

if (!cma_file_exists)
if (!cma_folder_exists(buf))
{
printf("template not found\n");
break;
Expand Down
19 changes: 18 additions & 1 deletion cmakeauto.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@

#ifdef _WIN32
#include <Windows.h>
#include <fileapi.h>

#define FILE_MAX_PATH _MAX_PATH
#define FILE_SEPERATOR "\\"
#define FILE_SEPERATOR_CHAR '\\'

typedef void *watchfolderhandle_t;
#elif __linux__
#include <sys/types.h>
#include <sys/stat.h>
Expand All @@ -22,15 +25,25 @@
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/inotify.h>

#ifdef __GNUC__
#define ALIGNAS(TYPE) __attribute__((aligned(__alignof__(TYPE))))
#else
#define ALIGNAS(TYPE) /* empty */
#endif

#define FILE_MAX_PATH PATH_MAX
#define FILE_SEPERATOR "/"
#define FILE_SEPERATOR_CHAR '/'

typedef int watchfolderhandle_t;
#else
#error unsupported platform
#endif

#define GERNERATOR_MAX_LEN 64
#define WATCHFOLDER_MAX_LEN 64

#ifdef __linux__
#define stricmp strcasecmp
Expand Down Expand Up @@ -105,7 +118,10 @@ typedef struct
char *extra_init_args;
char *extra_build_args;

void *watchfolderhandle;
char watchfolders[FILE_MAX_PATH + 1][WATCHFOLDER_MAX_LEN];
unsigned int watchfolders_count;
watchfolderhandle_t *watchfolderhandles;
unsigned int watchfolderhandles_count;
} CMakeAutoConfig;

/**
Expand All @@ -125,6 +141,7 @@ void cma_print_usage();
bool cma_abspath(char *buf, size_t size, const char *path);
bool cma_create_dir_include_existing(const char *path);
bool cma_file_exists(const char *path);
bool cma_folder_exists(const char *path);
bool cma_copy_file(const char *src, const char *dst);
bool cma_get_current_process_absfilepath(char *buf, size_t size);
bool cma_get_workdir(char *buf, size_t size);
Expand Down
Loading

0 comments on commit 3af19de

Please sign in to comment.