14#define DISABLE_DEBUGLOG
17#include "gwenbuild/buildctx/buildctx_p.h"
22#include <gwenhywfar/debug.h>
23#include <gwenhywfar/text.h>
24#include <gwenhywfar/directory.h>
35#define GWB_BUILDCTX_PROCESS_WAIT_TIMEOUT 10.0
83 if (GWB_BuildCmd_List2_GetSize(bctx->waitingQueue)==0) {
84 fprintf(stdout,
"Nothing to do.\n");
88 waitingJobs=GWB_BuildCmd_List2_GetSize(bctx->waitingQueue);
89 runningJobs=GWB_BuildCmd_List2_GetSize(bctx->runningQueue);
90 while(waitingJobs+runningJobs) {
95 if (startedCommands<0) {
102 if (changedCommands<0) {
108 if (startedCommands==0 && changedCommands==0) {
109 if (runningJobs==0) {
110 DBG_ERROR(
NULL,
"ERROR: No running jobs and none could be started, maybe circular dependencies?");
119 waitingJobs=GWB_BuildCmd_List2_GetSize(bctx->waitingQueue);
120 runningJobs=GWB_BuildCmd_List2_GetSize(bctx->runningQueue);
123 GWB_BuildCmd_List2_free(bctx->waitingQueue);
124 bctx->waitingQueue=
NULL;
125 GWB_BuildCmd_List2_free(bctx->runningQueue);
126 bctx->runningQueue=
NULL;
127 GWB_BuildCmd_List2_free(bctx->finishedQueue);
128 bctx->finishedQueue=
NULL;
141 numRunningJobs=GWB_BuildCmd_List2_GetSize(bctx->runningQueue);
143 fprintf(stderr,
"NOTICE: Waiting for %d jobs.\n", numRunningJobs);
144 while(numRunningJobs) {
145 int numChangedCommands;
149 if (numChangedCommands<0) {
152 numRunningJobs=GWB_BuildCmd_List2_GetSize(bctx->runningQueue);
154 if (numRunningJobs>0) {
158 delta=difftime(currentTime, startTime);
160 DBG_ERROR(
NULL,
"%d jobs still running after %f.1 seconds, aborting", numRunningJobs, delta);
177 GWB_BuildCmd_List2_free(bctx->waitingQueue);
178 bctx->waitingQueue=
NULL;
181 GWB_BuildCmd_List2_free(bctx->runningQueue);
182 bctx->runningQueue=
NULL;
185 GWB_BuildCmd_List2_free(bctx->finishedQueue);
186 bctx->finishedQueue=
NULL;
195 while( (bcmd=GWB_BuildCmd_List2_GetFront(cmdList)) ) {
196 GWB_BuildCmd_List2_PopFront(cmdList);
206 GWB_BUILD_CMD_LIST2_ITERATOR *it;
208 it=GWB_BuildCmd_List2_First(bctx->commandList);
212 bcmd=GWB_BuildCmd_List2Iterator_Data(it);
214 GWB_BUILD_SUBCMD_LIST *cmdList;
216 if (forPrepareCommands)
222 bcmd=GWB_BuildCmd_List2Iterator_Next(it);
224 GWB_BuildCmd_List2Iterator_free(it);
232 bctx->waitingQueue=GWB_BuildCmd_List2_new();
233 bctx->finishedQueue=GWB_BuildCmd_List2_new();
234 bctx->runningQueue=GWB_BuildCmd_List2_new();
241 GWB_BUILD_CMD_LIST2 *oldQueue;
246 oldQueue=bctx->waitingQueue;
247 bctx->waitingQueue=GWB_BuildCmd_List2_new();
249 while( (bcmd=GWB_BuildCmd_List2_GetFront(oldQueue)) ) {
251 GWB_BuildCmd_List2_PopFront(oldQueue);
252 if (started<maxStartAllowed) {
259 bctx->initialSourceDir);
261 bctx->initialSourceDir);
266 GWB_BuildCmd_List2_PushBack(bctx->finishedQueue, bcmd);
270 GWB_BuildCmd_List2_PushBack(bctx->runningQueue, bcmd);
282 GWB_BuildCmd_List2_PushBack(bctx->waitingQueue, bcmd);
285 GWB_BuildCmd_List2_PushBack(bctx->waitingQueue, bcmd);
287 GWB_BuildCmd_List2_free(oldQueue);
298 GWB_FILE_LIST2_ITERATOR *it;
300 it=GWB_File_List2_First(fileList);
308 file=GWB_File_List2Iterator_Data(it);
313 file=GWB_File_List2Iterator_Next(it);
316 GWB_File_List2Iterator_free(it);
335 if (currentCommand) {
337 uint32_t subCmdFlags;
345 DBG_INFO(
NULL,
"Input files newer than output files, rebuild needed");
358 DBG_INFO(
NULL,
"Dependencies flag NO rebuild needed (%d)", rv);
361 DBG_INFO(
NULL,
"Dependencies flag rebuild needed (%d)", rv);
375 time_t tiHighestInFileTime;
376 time_t tiLowestOutFileTime;
380 if (tiHighestInFileTime==0 || tiLowestOutFileTime==0) {
381 DBG_INFO(
NULL,
"Either input or output time not available");
384 if (tiHighestInFileTime>tiLowestOutFileTime)
410 else if (tiFile<tiLowest)
447 else if (tiFile>tiHighest)
490 const char *depFileName;
493 if (depFileName && firstOutFileName) {
507 DBG_DEBUG(
NULL,
"Could not load depend file \"%s\"", depFileName);
511 if (depFileName==
NULL) {
512 DBG_DEBUG(
NULL,
"No depFileName for %s", firstOutFileName?firstOutFileName:
"<no outfile name>");
514 if (firstOutFileName==
NULL) {
531 DBG_DEBUG(
NULL,
"%s: No modification time, need rebuild", fileName);
546 DBG_DEBUG(
NULL,
"No modification time for dependency \"%s\", need rebuild", s);
549 if (difftime(tFile, tCurrent)<0.0) {
550 DBG_DEBUG(
NULL,
"File \"%s\" is newer than \"%s\", rebuild needed", s, fileName);
558 DBG_DEBUG(
NULL,
"No dependency is newer than file \"%s\", NO rebuild needed", fileName);
575 if (currentCommand) {
587 const char *buildMessage;
590 if (GWB_BuildSubCmd_List_Previous(currentCommand)==
NULL) {
599 fprintf(stdout,
"%s [%s]\n", buildMessage, cmd);
601 fprintf(stdout,
"%s %s\n", cmd, args);
605 DBG_ERROR(
NULL,
"Error creating logfile path for output redirection (%d)", rv);
611 if (folder && *folder)
620 DBG_ERROR(
NULL,
"Error starting command process (%d)", pstate);
642 GWB_BUILD_CMD_LIST2 *oldRunningQueue;
647 oldRunningQueue=bctx->runningQueue;
648 bctx->runningQueue=GWB_BuildCmd_List2_new();
650 while( (bcmd=GWB_BuildCmd_List2_GetFront(oldRunningQueue)) ) {
655 GWB_BuildCmd_List2_PopFront(oldRunningQueue);
668 DBG_INFO(
NULL,
"Command exited with result %d, ignoring", result);
672 DBG_INFO(
NULL,
"Command exited with result %d", result);
683 GWB_BuildCmd_List2_PushBack(bctx->finishedQueue, bcmd);
689 GWB_BuildCmd_List2_PushBack(bctx->runningQueue, bcmd);
692 GWB_BuildCmd_List2_free(oldRunningQueue);
705 nextCommand=GWB_BuildSubCmd_List_Next(currentCommand);
708 GWB_BuildCmd_List2_PushBack(bctx->waitingQueue, bcmd);
711 GWB_BuildCmd_List2_PushBack(bctx->finishedQueue, bcmd);
719 GWB_FILE_LIST2 *outFileList;
723 GWB_FILE_LIST2_ITERATOR *it;
725 it=GWB_File_List2_First(outFileList);
729 file=GWB_File_List2Iterator_Data(it);
731 GWB_BUILD_CMD_LIST2 *waitingCommands;
736 file=GWB_File_List2Iterator_Next(it);
738 GWB_File_List2Iterator_free(it);
748 GWB_BUILD_CMD_LIST2_ITERATOR *it;
750 it=GWB_BuildCmd_List2_First(waitingCommands);
754 bcmd=GWB_BuildCmd_List2Iterator_Data(it);
757 bcmd=GWB_BuildCmd_List2Iterator_Next(it);
760 GWB_BuildCmd_List2Iterator_free(it);
768 const char *fileName;
774 if (stat(fileName, &sb)==-1) {
788 const char *buildMessage;
795 fprintf(stderr,
"Output from [%s]\n", buildMessage?buildMessage:(
exe?
exe:
"NONE"));
796 if (folder && *folder)
797 fprintf(stderr,
"make[%d]: Entering directory '%s'\n", ++
_commandLogNum, folder);
799 if (folder && *folder)
800 fprintf(stderr,
"make[%d]: Leaving directory '%s'\n",
_commandLogNum, folder);
GWEN_BUFFER * GWEN_Buffer_new(char *buffer, uint32_t size, uint32_t used, int take)
void GWEN_Buffer_Reset(GWEN_BUFFER *bf)
void GWEN_Buffer_free(GWEN_BUFFER *bf)
char * GWEN_Buffer_GetStart(const GWEN_BUFFER *bf)
GWB_FILE_LIST2 * GWB_BuildCmd_GetOutFileList2(const GWB_BUILD_CMD *bcmd)
GWB_BUILD_SUBCMD_LIST * GWB_BuildCmd_GetPrepareCommandList(const GWB_BUILD_CMD *bcmd)
void GWB_BuildCmd_SetCurrentProcess(GWB_BUILD_CMD *bcmd, GWEN_PROCESS *process)
void GWB_BuildCmd_SetCurrentCommand(GWB_BUILD_CMD *bcmd, GWB_BUILD_SUBCMD *cmd)
uint32_t GWB_BuildCmd_GetFlags(const GWB_BUILD_CMD *bcmd)
GWB_FILE_LIST2 * GWB_BuildCmd_GetInFileList2(const GWB_BUILD_CMD *bcmd)
int GWB_BuildCmd_DecBlockingFiles(GWB_BUILD_CMD *bcmd)
GWB_BUILD_SUBCMD * GWB_BuildCmd_GetCurrentCommand(const GWB_BUILD_CMD *bcmd)
GWB_BUILD_SUBCMD_LIST * GWB_BuildCmd_GetBuildCommandList(const GWB_BUILD_CMD *bcmd)
const char * GWB_BuildCmd_GetFolder(const GWB_BUILD_CMD *bcmd)
int GWB_BuildCmd_GetBlockingFiles(const GWB_BUILD_CMD *bcmd)
GWEN_PROCESS * GWB_BuildCmd_GetCurrentProcess(const GWB_BUILD_CMD *bcmd)
struct GWB_BUILD_CMD GWB_BUILD_CMD
#define GWB_BUILD_CMD_FLAGS_CHECK_DATES
#define GWB_BUILD_CMD_FLAGS_DEL_OUTFILES
int GWB_BuildCtx_CreateAndSetLogFilenameForSubCmd(GWB_BUILD_CONTEXT *bctx, GWB_BUILD_SUBCMD *cmd)
struct GWB_BUILD_CONTEXT GWB_BUILD_CONTEXT
int GWB_BuildCtx_FillWaitingQueue(GWB_BUILD_CONTEXT *bctx, const char *builderName)
int GWB_BuildCtx_SetupDependencies(GWB_BUILD_CONTEXT *bctx)
GWEN_STRINGLIST * GWB_BuildCtx_ReadAndTranslateDepfile(const char *folder, const char *fileName)
static int _startCommand(GWB_BUILD_CONTEXT *bctx, GWB_BUILD_CMD *bcmd, const GWEN_STRINGLIST *slOutFiles)
static int _checkWaitingQueue(GWB_BUILD_CONTEXT *bctx, int maxStartAllowed)
static void _abortCommandsInQueue(GWB_BUILD_CMD_LIST2 *cmdList)
static void _signalJobFinished(GWB_BUILD_CMD *bcmd)
static int _needRunCurrentCommand(GWB_BUILD_CMD *bcmd, const GWEN_STRINGLIST *slInFiles, const GWEN_STRINGLIST *slOutFiles)
static void _finishCurrentCommand(GWB_BUILD_CONTEXT *bctx, GWB_BUILD_CMD *bcmd, GWB_BUILD_SUBCMD *currentCommand)
int GWB_BuildCtx_Run(GWB_BUILD_CONTEXT *bctx, int maxConcurrentJobs, int usePrepareCommands, const char *builderName)
static void _createCommandQueues(GWB_BUILD_CONTEXT *bctx)
static time_t _getLowestModificationTime(const GWEN_STRINGLIST *slFiles)
static time_t _getHighestModificationTime(const GWEN_STRINGLIST *slFiles)
static void _printCmdOutputIfNotEmptyAndDeleteFile(GWB_BUILD_CMD *cmd, GWB_BUILD_SUBCMD *subCmd)
static void _unlinkFilesInStringList(const GWEN_STRINGLIST *slFiles)
static void _decBlockingFilesInWaitingBuildCommands(GWB_BUILD_CMD_LIST2 *waitingCommands)
static int _inFilesNewerThanOutFiles(const GWEN_STRINGLIST *slInFiles, const GWEN_STRINGLIST *slOutFiles)
static int _checkDatesOfFileAgainstList(const char *fileName, const GWEN_STRINGLIST *sl)
static int _checkRunningQueue(GWB_BUILD_CONTEXT *bctx)
static void _abortAllCommands(GWB_BUILD_CONTEXT *bctx)
static int _commandLogNum
static int _waitForRunningJobs(GWB_BUILD_CONTEXT *bctx)
GWEN_STRINGLIST * _fileListToTopBuildDirStringList(const char *initialSourceDir, GWB_FILE_LIST2 *fileList)
static int _checkDependencies(GWB_BUILD_CMD *bcmd, GWB_BUILD_SUBCMD *subCmd, const char *firstOutFileName)
static void _setupCommands(GWB_BUILD_CONTEXT *bctx, int forPrepareCommands)
#define GWB_BUILDCTX_PROCESS_WAIT_TIMEOUT
uint32_t GWB_BuildSubCmd_GetFlags(const GWB_BUILD_SUBCMD *cmd)
const char * GWB_BuildSubCmd_GetArguments(const GWB_BUILD_SUBCMD *cmd)
const char * GWB_BuildSubCmd_GetDepFilePath(const GWB_BUILD_SUBCMD *cmd)
const char * GWB_BuildSubCmd_GetLogFilename(const GWB_BUILD_SUBCMD *cmd)
const char * GWB_BuildSubCmd_GetCommand(const GWB_BUILD_SUBCMD *cmd)
const char * GWB_BuildSubCmd_GetBuildMessage(const GWB_BUILD_SUBCMD *cmd)
#define GWB_BUILD_SUBCMD_FLAGS_CHECK_DEPENDS
struct GWB_BUILD_SUBCMD GWB_BUILD_SUBCMD
#define GWB_BUILD_SUBCMD_FLAGS_IGNORE_RESULT
#define DBG_INFO(dbg_logger, format,...)
#define DBG_ERROR(dbg_logger, format,...)
#define DBG_DEBUG(dbg_logger, format,...)
#define GWEN_ERROR_TIMEOUT
#define GWEN_ERROR_GENERIC
void GWB_File_WriteFileNameToTopBuildDirString(const GWB_FILE *file, const char *initialSourceDir, GWEN_BUFFER *fbuf)
GWEN_STRINGLIST * GWB_File_FileListToTopBuildDirStringList(const GWB_FILE_LIST2 *fileList, const char *initialSourceDir)
GWB_BUILD_CMD_LIST2 * GWB_File_GetWaitingBuildCmdList2(const GWB_FILE *f)
struct GWEN_BUFFER GWEN_BUFFER
A dynamically resizeable text buffer.
time_t GWBUILD_GetModificationTimeOfFile(const char *filename)
GWENHYWFAR_API int GWEN_Process_GetResult(GWEN_PROCESS *pr)
GWENHYWFAR_API void GWEN_Process_SetFolder(GWEN_PROCESS *pr, const char *s)
GWENHYWFAR_API GWEN_PROCESS * GWEN_Process_new(void)
GWENHYWFAR_API GWEN_PROCESS_STATE GWEN_Process_Start(GWEN_PROCESS *pr, const char *prg, const char *args)
GWENHYWFAR_API void GWEN_Process_SetFilenameStdOut(GWEN_PROCESS *pr, const char *s)
GWENHYWFAR_API GWEN_PROCESS_STATE GWEN_Process_CheckState(GWEN_PROCESS *pr)
GWENHYWFAR_API void GWEN_Process_SetFilenameStdErr(GWEN_PROCESS *pr, const char *s)
struct GWEN_PROCESS GWEN_PROCESS
@ GWEN_ProcessStateRunning
@ GWEN_ProcessStateExited
void GWEN_StringList_free(GWEN_STRINGLIST *sl)
const char * GWEN_StringListEntry_Data(const GWEN_STRINGLISTENTRY *se)
GWEN_STRINGLISTENTRY * GWEN_StringListEntry_Next(const GWEN_STRINGLISTENTRY *se)
unsigned int GWEN_StringList_Count(const GWEN_STRINGLIST *sl)
int GWEN_StringList_AppendString(GWEN_STRINGLIST *sl, const char *s, int take, int checkDouble)
const char * GWEN_StringList_FirstString(const GWEN_STRINGLIST *l)
GWEN_STRINGLISTENTRY * GWEN_StringList_FirstEntry(const GWEN_STRINGLIST *sl)
GWEN_STRINGLIST * GWEN_StringList_new(void)
struct GWEN_STRINGLISTENTRYSTRUCT GWEN_STRINGLISTENTRY
struct GWEN_STRINGLISTSTRUCT GWEN_STRINGLIST
int GWEN_SyncIo_Helper_ReadFile(const char *fName, GWEN_BUFFER *dbuf)