diff --git a/Makefile b/Makefile index 1e1fb81..181a353 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ pkgdoc_DATA = LICENSE README.md screenshot.png man1_MANS = make2graph.1 makefile2graph.1 CFLAGS ?= -O3 -Wall +LDLIBS ?= -lm .PHONY: all clean install test .DELETE_ON_ERROR: diff --git a/README.md b/README.md index 821fb89..71bf7b8 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ sub-makefiles are not supported. ## History +* 2022-12-17 bumped gexf schema version, added viz attributes see [GEXF File Format](https://gexf.net/schema.html) * 2014-12-31 added option `--format`, removed otpions 'x' and 'd' * 2014-12-22 added 'deep' output. I need this when I'm working on a cluster and I need to know the deepest independent targets that should be make. * 2014-10-07 print version diff --git a/make2graph.c b/make2graph.c index e82475e..99b685e 100644 --- a/make2graph.c +++ b/make2graph.c @@ -40,12 +40,15 @@ #include #include #include +#include /* version */ -#define M2G_VERSION "1.5.0" +#define M2G_VERSION "1.6.0" #define OUT_OF_MEMORY do { fprintf(stderr,"%s: %d : OUT_OF_MEMORY.\n",__FILE__,__LINE__); exit(EXIT_FAILURE);} while(0) +#define GEXF_NODE_VIZ_SIZE 10.0 + /* as https://github.com/lindenb/makefile2graph/issues/9 */ static char* StrNDup (const char *s, size_t n) { @@ -70,6 +73,11 @@ enum output_type { output_list }; +enum layout_type { + layout_none, + layout_circular + }; + /** a Target */ typedef struct target_t { @@ -391,14 +399,34 @@ static void DumpGraphAsDot(GraphPtr g,FILE* out) fputs("}\n",out); } +void PositionNodeCircular(FILE* out,double angle,double radius) + { + fputs("\">\n",out); + + char viz_size[100]; + snprintf(viz_size,100," \n",GEXF_NODE_VIZ_SIZE); + fputs(viz_size,out); + + char viz_position[100]; + double pos_x = radius * cos(angle); + double pos_y = radius * sin(angle); + snprintf(viz_position,100," \n",pos_y,pos_x); + fputs(viz_position,out); + fputs(" \n",out); + } + +void PositionNodeNone(FILE* out) + { + fputs("\"/>\n",out); + } /** export a Gephi / Gexf */ -void DumpGraphAsGexf(GraphPtr g,FILE* out) +void DumpGraphAsGexf(GraphPtr g,FILE* out,int layout) { size_t i=0,j=0,k=0UL; fputs("\n",out); - fputs("\n",out); + fputs("\n",out); fputs(" \n",out); fputs(" https://github.com/lindenb/makefile2graph version:" M2G_VERSION "\n",out); fputs(" Creates a graph from a Makefile\n",out); @@ -406,6 +434,14 @@ void DumpGraphAsGexf(GraphPtr g,FILE* out) fputs(" \n",out); fputs(" \n",out); fputs(" \n",out); + + double node_count = (double)(g->target_count); + double circumference = (double)(GEXF_NODE_VIZ_SIZE * 10.0 * g->target_count); + double radius = circumference / (2 * (2 * asin(1.0))); + + double angle_seg = 360 / node_count; + double angle_cur = 0; + for(i=0; i< g->target_count; ++i) { j=0UL; @@ -428,7 +464,13 @@ void DumpGraphAsGexf(GraphPtr g,FILE* out) } ++j; } - fputs("\"/>\n",out); + switch(layout) + { + case layout_circular: PositionNodeCircular(out,angle_cur,radius); break; + default: PositionNodeNone(out); break; + } + + angle_cur += angle_seg; } fputs(" \n",out); fputs(" \n",out); @@ -519,6 +561,9 @@ static void usage(FILE* out) fputs("\t\t(x)xml (g)exf XML output (gexf)\n",out); fputs("\t\t(E) print the deepest indepedent targets.\n",out); fputs("\t\t(L)ist all targets.\n",out); + fputs("\t-l|--layout (layout)\n",out); + fputs("\t\t(n)op ... don't add any layout config (default).\n",out); + fputs("\t\t(c)ircular ... position nodes in a circle.\n",out); fputs("\t-b|--basename only print file basename.\n",out); fputs("\t-s|--suffix only print file extension.\n",out); fputs("\t-r|--root show node.\n",out); @@ -529,6 +574,7 @@ static void usage(FILE* out) int main(int argc,char** argv) { int out_format = output_dot; + int layout = layout_none; int print_basename_only=0; int print_suffix_only=0; int show_root=0; @@ -538,6 +584,7 @@ int main(int argc,char** argv) static struct option long_options[] = { {"format", required_argument ,0, 'f'}, + {"layout", optional_argument ,0, 'l'}, {"help", no_argument, 0, 'h'}, {"basename", no_argument, 0, 'b'}, {"suffix", no_argument, 0, 's'}, @@ -546,7 +593,7 @@ int main(int argc,char** argv) {0, 0, 0, 0} }; int option_index = 0; - int c = getopt_long (argc, argv, "hbsrvf:", + int c = getopt_long (argc, argv, "hbsrvf:l:", long_options, &option_index); if (c == -1) break; switch (c) @@ -570,6 +617,16 @@ int main(int argc,char** argv) } break; } + case 'l': + { + switch(optarg[0]) + { + case 'c': layout = layout_circular; break; + /* TODO: case 'r': layout = layout_random; break; */ + default: layout = layout_none; break; + } + break; + } case 'h': usage(stdout); return EXIT_SUCCESS; case 'b': print_basename_only=1; break; case 's': print_suffix_only=1; break; @@ -621,7 +678,7 @@ int main(int argc,char** argv) switch(out_format) { case output_gexf : - DumpGraphAsGexf(app,stdout); + DumpGraphAsGexf(app,stdout,layout); break; case output_deep : DumpGraphAsDeep(app,stdout);