gwenhywfar  5.10.1
gwenbuild/main.c
Go to the documentation of this file.
1 /***************************************************************************
2  begin : Mon Feb 08 2021
3  copyright : (C) 2021 by Martin Preuss
4  email : martin@libchipcard.de
5 
6  ***************************************************************************
7  * Please see toplevel file COPYING for license details *
8  ***************************************************************************/
9 
10 #ifdef HAVE_CONFIG_H
11 # include <config.h>
12 #endif
13 
14 
16 #include "gwenbuild/filenames.h"
17 #include "utils.h"
18 #include "c_setup.h"
19 #include "c_prepare.h"
20 #include "c_build.h"
21 #include "c_install.h"
22 #include "c_clean.h"
23 #include "c_dist.h"
24 
25 #include <gwenhywfar/gwenhywfar.h>
26 #include <gwenhywfar/cgui.h>
27 #include <gwenhywfar/debug.h>
28 #include <gwenhywfar/args.h>
29 #include <gwenhywfar/i18n.h>
30 #include <gwenhywfar/text.h>
31 #include <gwenhywfar/directory.h>
32 
33 #include <unistd.h>
34 
35 #ifdef HAVE_SIGNAL_H
36 # include <signal.h>
37 #endif
38 
39 
40 
41 #define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
42 #define I18S(msg) msg
43 
44 
45 #define ARGS_COMMAND_SETUP 0x0001
46 #define ARGS_COMMAND_PREPARE 0x0002
47 #define ARGS_COMMAND_BUILD 0x0004
48 #define ARGS_COMMAND_REPEAT_SETUP 0x0008
49 #define ARGS_COMMAND_INSTALL 0x0010
50 #define ARGS_COMMAND_CLEAN 0x0020
51 #define ARGS_COMMAND_DIST 0x0040
52 
53 
54 
55 static int _readArgsIntoDb(int argc, char **argv, GWEN_DB_NODE *db);
56 static int _handleStringArgument(int argc, char **argv, int *pIndex, const char *sArg, const char *sArgId,
57  const char *sVarName, GWEN_DB_NODE *db);
58 static void _printHelpScreen();
59 
60 
61 
62 
63 #ifdef HAVE_SIGNAL_H
64 
65 # ifdef _POSIX_C_SOURCE
66 struct sigaction sigActionChild;
67 # endif
68 
69 
70 void _signalHandler(int s) {
71  switch(s) {
72 #ifdef _POSIX_C_SOURCE
73  case SIGCHLD:
74  //fprintf(stderr, "Child exited %d\n", s);
75  break;
76 #endif
77  default:
78  fprintf(stderr, "Received unhandled signal %d\n", s);
79  break;
80  }
81  signal(s, _signalHandler);
82 }
83 
84 
85 
86 #if _POSIX_C_SOURCE
87 int _setSingleSignalHandler(struct sigaction *sa, int sig)
88 {
89  sa->sa_handler=_signalHandler;
90  sigemptyset(&sa->sa_mask);
91  sa->sa_flags=0;
92  if (sigaction(sig, sa, 0)) {
93  DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
94  return GWEN_ERROR_GENERIC;
95  }
96  return 0;
97 }
98 #endif
99 
100 
101 
102 int _setSignalHandlers() {
103 #ifdef _POSIX_C_SOURCE
104  int rv;
105 
106  rv=_setSingleSignalHandler(&sigActionChild, SIGCHLD);
107  if (rv<0) {
108  DBG_INFO(NULL, "here (%d)", rv);
109  return rv;
110  }
111 #endif
112 
113  return 0;
114 }
115 
116 #endif
117 
118 
119 
120 
121 int main(int argc, char **argv)
122 {
123  GWEN_DB_NODE *dbArgs;
124  int rv;
125  int err;
126  uint32_t commands=0;
127  const char *s;
128  GWEN_GUI *gui;
129 
130 #if defined(HAVE_SIGNAL_H) && defined(_POSIX_C_SOURCE)
131  signal(SIGCHLD, _signalHandler);
132  //_setSignalHandlers();
133 #endif
134 
135  err=GWEN_Init();
136  if (err) {
137  fprintf(stderr, "Could not initialize Gwenhywfar.\n");
138  return 2;
139  }
140 
141  gui=GWEN_Gui_CGui_new();
142  GWEN_Gui_SetGui(gui);
143 
144  GWEN_Logger_Open(NULL, "gwenbuild", 0,
147 
149 
150  dbArgs=GWEN_DB_Group_new("args");
151  rv=_readArgsIntoDb(argc, argv, dbArgs);
152  if (rv<0 || rv==1) {
153  return 1;
154  }
155 
156  s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
157  if (s && *s) {
158  GWEN_LOGGER_LEVEL level;
159 
160  level=GWEN_Logger_Name2Level(s);
161  if (level==GWEN_LoggerLevel_Unknown) {
162  }
163  else
164  GWEN_Logger_SetLevel(NULL, level);
165  }
166 
167  commands|=GWEN_DB_GetIntValue(dbArgs, "setup", 0, 0)?ARGS_COMMAND_SETUP:0; /* -s */
168  commands|=GWEN_DB_GetIntValue(dbArgs, "repeatSetup", 0, 0)?ARGS_COMMAND_REPEAT_SETUP:0; /* -r */
169  commands|=GWEN_DB_GetIntValue(dbArgs, "prepare", 0, 0)?ARGS_COMMAND_PREPARE:0; /* -p */
170  commands|=GWEN_DB_GetIntValue(dbArgs, "build", 0, 0)?ARGS_COMMAND_BUILD:0; /* -b or no opts */
171  commands|=GWEN_DB_GetIntValue(dbArgs, "install", 0, 0)?ARGS_COMMAND_INSTALL:0; /* -i */
172  commands|=GWEN_DB_GetIntValue(dbArgs, "clean", 0, 0)?ARGS_COMMAND_CLEAN:0; /* -c */
173  commands|=GWEN_DB_GetIntValue(dbArgs, "dist", 0, 0)?ARGS_COMMAND_DIST:0; /* -d */
174 
175  if (commands & ARGS_COMMAND_SETUP) {
176  rv=GWB_Setup(dbArgs);
177  if (rv!=0) {
178  fprintf(stderr, "ERROR: Error on setup build environment.\n");
179  return rv;
180  }
181  }
182 
183  if (commands & ARGS_COMMAND_REPEAT_SETUP) {
185  if (rv<0) {
186  fprintf(stderr, "ERROR: Error on repeating setup.\n");
187  return rv;
188  }
189  }
190 
191  if (commands & ARGS_COMMAND_PREPARE) {
192  rv=GWB_Prepare(dbArgs);
193  if (rv!=0) {
194  fprintf(stderr, "ERROR: Error on preparing build environment.\n");
195  return rv;
196  }
197  }
198 
199  if ((commands & ARGS_COMMAND_BUILD) || (commands==0)) {
200  rv=GWB_Build(dbArgs);
201  if (rv!=0) {
202  fprintf(stderr, "ERROR: Error on building.\n");
203  return rv;
204  }
205  }
206 
207  if (commands & ARGS_COMMAND_INSTALL) {
208  rv=GWB_InstallFiles(GWBUILD_FILE_INSTALLFILES, getenv("DESTDIR"));
209  if (rv!=0) {
210  fprintf(stderr, "ERROR: Error on installing.\n");
211  return rv;
212  }
213  }
214 
215  if (commands & ARGS_COMMAND_DIST) {
216  rv=GWB_MkDist();
217  if (rv!=0) {
218  fprintf(stderr, "ERROR: Error on creating dist file.\n");
219  return rv;
220  }
221  }
222 
223  if (commands & ARGS_COMMAND_CLEAN) {
225  if (rv!=0) {
226  fprintf(stderr, "ERROR: Error on cleaning generated files.\n");
227  return rv;
228  }
229  }
230 
231 
232  err=GWEN_Fini();
233  if (err) {
234  fprintf(stderr,
235  "WARNING: Could not deinitialize Gwenhywfar.\n");
236  }
237 
238  return 0;
239 }
240 
241 
242 
243 int _handleStringArgument(int argc, char **argv, int *pIndex, const char *sArg, const char *sArgId, const char *sVarName, GWEN_DB_NODE *db)
244 {
245  int i;
246 
247  i=*pIndex;
248  if (*sArg==0) {
249  i++;
250  if (i>=argc) {
251  DBG_ERROR(NULL, "Missing argument for \"%s\"", sArgId);
252  return GWEN_ERROR_INVALID;
253  }
254  sArg=argv[i];
255  }
256  if (sArg && *sArg)
257  GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_DEFAULT, sVarName, sArg);
258  *pIndex=i;
259  return 0;
260 }
261 
262 
263 
264 int _readArgsIntoDb(int argc, char **argv, GWEN_DB_NODE *db)
265 {
266  int i=1;
267  int help=0;
268 
269  while(i<argc) {
270  const char *s;
271  int val;
272 
273  s=argv[i];
274  if (s) {
275  if (*s!='-') {
276 #if 0
277  /* no option, probably gwbuild target */
278  GWEN_DB_SetCharValue(db, 0, "target", s);
279 #else
280  fprintf(stderr, "Specifying build target not yet supported.\n");
281  return GWEN_ERROR_GENERIC;
282 #endif
283  }
284  else {
285  int rv;
286 
287  if (strncmp(s, "-O", 2)==0) {
288  rv=_handleStringArgument(argc, argv, &i, s+2, "-O", "option",db);
289  if (rv<0)
290  return rv;
291  }
292  if (strncmp(s, "-B", 2)==0) {
293  rv=_handleStringArgument(argc, argv, &i, s+2, "-B", "builder",db);
294  if (rv<0)
295  return rv;
296  }
297  if (strncmp(s, "-L", 2)==0) {
298  rv=_handleStringArgument(argc, argv, &i, s+2, "-L", "loglevel",db);
299  if (rv<0)
300  return rv;
301  }
302  if (strncmp(s, "-C", 2)==0) {
303  rv=_handleStringArgument(argc, argv, &i, s+2, "-C", "crossCompileFor",db);
304  if (rv<0)
305  return rv;
306  }
307  else if (strcmp(s, "--dump")==0)
309  else if (strcmp(s, "--static")==0)
311  else if (strcmp(s, "--help")==0) {
313  help=1;
314  }
315  else if (strcmp(s, "-p")==0)
317  else if (strcmp(s, "-s")==0) {
319  rv=_handleStringArgument(argc, argv, &i, s+2, "-s", "folder", db);
320  if (rv<0)
321  return rv;
322  }
323  else if (strcmp(s, "-r")==0)
324  GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "repeatSetup", 1);
325  else if (strcmp(s, "-b")==0)
327  else if (strcmp(s, "-i")==0)
329  else if (strcmp(s, "-c")==0)
331  else if (strcmp(s, "-d")==0)
333  else if (strncmp(s, "-j", 2)==0) {
334  /* jobs */
335  s+=2;
336  if (*s==0) {
337  i++;
338  if (i>=argc) {
339  DBG_ERROR(NULL, "Missing argument for \"-j\"");
340  return GWEN_ERROR_INVALID;
341  }
342  s=argv[i];
343  }
344  if (1!=sscanf(s, "%d", &val)) {
345  DBG_ERROR(NULL, "Non-integer argument for \"-j\"");
346  return GWEN_ERROR_INVALID;
347  }
349  }
350  }
351  }
352  i++;
353  } /* while */
354 
355  if (help) {
357  return 1;
358  }
359 
360  return 0;
361 }
362 
363 
364 
366 {
367  fprintf(stdout,
368  "\n"
369  "Gwenhywfar Build Tool " GWENHYWFAR_VERSION_FULL_STRING "\n"
370  "\n"
371  "Building a project (e.g. compiling and linking) is done in multiple steps.\n"
372  "\n"
373  "1. Setup Build Environment\n"
374  "-------------------------\n"
375  "A. Create files named 0BUILD inside your project (see project AqFinance for\n"
376  "example files).\n"
377  "B. Create an empty folder and change into it (all next commands are run\n"
378  "from there).\n"
379  "You might want to use a folder like 'build' inside the source tree of\n"
380  "your project.\n"
381  "C. run\n"
382  " gwbuild -s PATH_TO_SOURCE_TREE\n"
383  "e.g. gwbuild -s ..\n"
384  "\n"
385  "2. Prepare Buidling\n"
386  "-------------------\n"
387  " gwbuild -p\n"
388  "This is only needed if your project uses typemaker2 to generate c-sources from\n"
389  "XML files.\n"
390  "This command makes typemaker2 create its derived type description files needed\n"
391  "when referencing\n"
392  "typemaker2 generated types inside another typemaker2 generated type.\n"
393  "\n"
394  "3. Build All Targets\n"
395  "--------------------------\n"
396  " gwbuild\n"
397  "This command builds typemaker2 source files first (if needed) and then all\n"
398  "other targets.\n"
399  "A single process is used to compile and link the project files.\n"
400  "If you have multiple processor cores/threads you can build multiple files in\n"
401  "parallel:\n"
402  " gwbuild -j14\n"
403  "This command uses 14 processes in parallel.\n"
404  "The step can be repeated as often as needed. It will automatically check for\n"
405  "changed files and try to only re-compile/link those modified files and others\n"
406  "which depend on them.\n"
407  "If you change a 0BUILD file gwbuild will automatically call the setup step\n"
408  "using the same\n"
409  "arguments given to the last setup command (-s). This typically leads to all\n"
410  "files being re-build.\n"
411  "\n"
412  "Option List\n"
413  "-----------\n"
414  "-s FOLDER setup build environment (arg: source folder path)\n"
415  "-p run preparation commands (needed e.g. if typemaker2 is used)\n"
416  "-b build targets\n"
417  "-i install files\n"
418  "-c cleanup; delete generated files\n"
419  "-r repeat setup command using the same arguments given to last setup\n"
420  "-d make distribution folder (you need to run tar yourself for now)\n"
421  "-Oname=value specify options (can occur multiple times)\n"
422  "-Bname Only run commands for the given build (mostly used with\n"
423  " 'tm2builder')\n"
424  "-Lname Set loglevel (debug, info, notice, warn, error)\n"
425  "-Cname Crosscompile for given environment (e-g- 'x86_64-w64-mingw32')\n"
426  "-jvalue Use the given number of parallel process for building\n"
427  "--static Generate static libs for InstallLibrary targets\n"
428  );
429 }
430 
431 
432 
433 
#define GWEN_DB_FLAGS_OVERWRITE_VARS
Definition: db.h:121
#define ARGS_COMMAND_CLEAN
int GWB_Setup(GWEN_DB_NODE *dbArgs)
Definition: c_setup.c:45
struct GWEN_DB_NODE GWEN_DB_NODE
Definition: db.h:228
int GWB_RepeatLastSetup(const char *fileName)
Definition: c_setup.c:159
#define GWEN_ERROR_INVALID
Definition: error.h:67
void GWEN_Logger_SetLevel(const char *logDomain, GWEN_LOGGER_LEVEL l)
Definition: logger.c:627
#define ARGS_COMMAND_REPEAT_SETUP
GWEN_LOGGER_LEVEL
Definition: logger.h:64
#define NULL
Definition: binreloc.c:300
#define GWBUILD_FILE_INSTALLFILES
Definition: filenames.h:19
#define ARGS_COMMAND_SETUP
GWEN_LOGGER_LEVEL GWEN_Logger_Name2Level(const char *name)
Definition: logger.c:697
#define ARGS_COMMAND_DIST
#define ARGS_COMMAND_INSTALL
int GWB_Build(GWEN_DB_NODE *dbArgs)
Definition: c_build.c:26
#define GWBUILD_FILE_ARGS
Definition: filenames.h:20
int GWB_Clean(const char *fname)
Definition: c_clean.c:27
#define GWEN_ERROR_GENERIC
Definition: error.h:62
const char * GWEN_DB_GetCharValue(GWEN_DB_NODE *n, const char *path, int idx, const char *defVal)
Definition: db.c:971
#define GWBUILD_FILE_FILES
Definition: filenames.h:16
int GWEN_Fini(void)
Definition: gwenhywfar.c:303
int GWEN_Logger_Open(const char *logDomain, const char *ident, const char *file, GWEN_LOGGER_LOGTYPE logtype, GWEN_LOGGER_FACILITY facility)
Definition: logger.c:225
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
int GWB_Prepare(GWEN_UNUSED GWEN_DB_NODE *dbArgs)
Definition: c_prepare.c:27
int GWB_MkDist()
Definition: c_dist.c:37
#define ARGS_COMMAND_PREPARE
int GWEN_DB_SetCharValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, const char *val)
Definition: db.c:997
#define ARGS_COMMAND_BUILD
int main(int argc, char **argv)
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:181
static int _readArgsIntoDb(int argc, char **argv, GWEN_DB_NODE *db)
struct GWEN_GUI GWEN_GUI
Definition: gui.h:176
int GWEN_DB_GetIntValue(GWEN_DB_NODE *n, const char *path, int idx, int defVal)
Definition: db.c:1163
GWEN_DB_NODE * GWEN_DB_Group_new(const char *name)
Definition: db.c:173
int GWEN_DB_SetIntValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, int val)
Definition: db.c:1202
#define GWENHYWFAR_VERSION_FULL_STRING
Definition: version.h:38
void GWEN_Gui_SetGui(GWEN_GUI *gui)
Definition: gui.c:170
int GWEN_Init(void)
Definition: gwenhywfar.c:92
GWEN_GUI * GWEN_Gui_CGui_new(void)
Definition: cgui.c:74
int GWB_InstallFiles(const char *fileName, const char *destDir)
Definition: c_install.c:25
static void _printHelpScreen()
static int _handleStringArgument(int argc, char **argv, int *pIndex, const char *sArg, const char *sArgId, const char *sVarName, GWEN_DB_NODE *db)
#define GWEN_DB_FLAGS_DEFAULT
Definition: db.h:168