Blob Blame History Raw
/*******************************************************************/
/*  sbpython2: external configurable build project for Python-2.7. */
/*  Copyright (C) 2018  SysDeer Technologies, LLC                  */
/*  Released under the Standard MIT License; see COPYING.SBPYTHON2.*/
/*******************************************************************/

/*******************************************************************/
/* pyexts.c: a simple development-time utility for generating      */
/* make rules for python's extension modules. The utility is       */
/* included with the sbpython2 project for reference only.         */
/*                                                                 */
/* cc -std=c99 -D_XOPEN_SOURCE=700 pyexts.c                        */
/*******************************************************************/

#include <stdio.h>
#include <string.h>

#define PYEXT_LIST(...)                   (const char *[]){__VA_ARGS__,0}
#define PYEXT_SIMPLE(name,...)            {name,PYEXT_LIST(__VA_ARGS__),0,0,0,0}

#define PYEXT_COMMON(name,hvar,lvar,...)  {name,PYEXT_LIST(__VA_ARGS__), \
                                           PYEXT_LIST(hvar),0,           \
                                           PYEXT_LIST(lvar),0}

#define PYEXT_ALTSTD(name,cstd,...)       {name,PYEXT_LIST(__VA_ARGS__), \
                                           0,PYEXT_LIST(cstd),0,0}

struct pyext_meta {
	const char *	name;
	const char **	srcs;
	const char **	hdrs;
	const char **	cstd;
	const char **	vars;
	const char **	deps;
};

static const struct pyext_meta pyexts[] = {
	PYEXT_SIMPLE("_multibytecodec","cjkcodecs/multibytecodec"),
	PYEXT_SIMPLE("_codecs_cn",     "cjkcodecs/_codecs_cn"),
	PYEXT_SIMPLE("_codecs_hk",     "cjkcodecs/_codecs_hk"),
	PYEXT_SIMPLE("_codecs_jp",     "cjkcodecs/_codecs_jp"),
	PYEXT_SIMPLE("_codecs_kr",     "cjkcodecs/_codecs_kr"),
	PYEXT_SIMPLE("_codecs_tw",     "cjkcodecs/_codecs_tw"),
	PYEXT_SIMPLE("_codecs_iso2022","cjkcodecs/_codecs_iso2022"),

	PYEXT_SIMPLE("_bisect",        "_bisectmodule"),
	PYEXT_SIMPLE("_collections",   "_collectionsmodule"),
	PYEXT_SIMPLE("_csv",           "_csv"),
	PYEXT_SIMPLE("_ctypes_test",   "_ctypes/_ctypes_test"),
	PYEXT_SIMPLE("_functools",     "_functoolsmodule"),
	PYEXT_SIMPLE("_heapq",         "_heapqmodule"),
	PYEXT_SIMPLE("_hotshot",       "_hotshot"),
	PYEXT_SIMPLE("_json",          "_json"),
	PYEXT_SIMPLE("_locale",        "_localemodule"),
	PYEXT_SIMPLE("_lsprof",        "_lsprof","rotatingtree"),
	PYEXT_SIMPLE("_random",        "_randommodule"),
	PYEXT_SIMPLE("_socket",        "socketmodule","timemodule"),
	PYEXT_SIMPLE("_struct",        "_struct"),
	PYEXT_SIMPLE("_testcapi",      "_testcapimodule"),

	PYEXT_SIMPLE("array",          "arraymodule"),
	PYEXT_SIMPLE("audioop",        "audioop"),
	PYEXT_SIMPLE("binascii",       "binascii"),
	PYEXT_SIMPLE("cPickle",        "cPickle"),
	PYEXT_SIMPLE("cStringIO",      "cStringIO"),
	PYEXT_SIMPLE("cmath",          "cmathmodule","_math"),
	PYEXT_SIMPLE("crypt",          "cryptmodule"),
	PYEXT_SIMPLE("datetime",       "datetimemodule","timemodule"),
	PYEXT_SIMPLE("fcntl",          "fcntlmodule"),
	PYEXT_SIMPLE("future_builtins","future_builtins"),
	PYEXT_SIMPLE("grp",            "grpmodule"),
	PYEXT_SIMPLE("itertools",      "itertoolsmodule"),
	PYEXT_SIMPLE("math",           "mathmodule","_math"),
	PYEXT_SIMPLE("mmap",           "mmapmodule"),
	PYEXT_SIMPLE("operator",       "operator"),
	PYEXT_SIMPLE("ossaudiodev",    "ossaudiodev"),
	PYEXT_SIMPLE("parser",         "parsermodule"),
	PYEXT_SIMPLE("resource",       "resource"),
	PYEXT_SIMPLE("select",         "selectmodule"),
	PYEXT_SIMPLE("spwd",           "spwdmodule"),
	PYEXT_SIMPLE("strop",          "stropmodule"),
	PYEXT_SIMPLE("syslog",         "syslogmodule"),
	PYEXT_SIMPLE("termios",        "termios"),
	PYEXT_SIMPLE("time",           "timemodule"),
	PYEXT_SIMPLE("unicodedata",    "unicodedata"),

	PYEXT_COMMON("_curses",        "$(CFLAGS_NCURSES)", "$(LDFLAGS_NCURSES)",  "_cursesmodule"),
	PYEXT_COMMON("_curses_panel",  "$(CFLAGS_NCURSES)", "$(LDFLAGS_NCURSES)",  "_curses_panel"),
	PYEXT_COMMON("_elementtree",   "-UVERSION",         "-lexpat",             "_elementtree"),
	PYEXT_COMMON("_hashlib",       0,                   "-lssl -lcrypto",      "_hashopenssl"),
	PYEXT_COMMON("_ssl",           0,                   "-lssl -lcrypto",      "_ssl"),
	PYEXT_COMMON("bz2",            0,                   "-lbz2",               "bz2module"),
	PYEXT_COMMON("gdbm",           0,                   "-lgdbm",              "gdbmmodule"),
	PYEXT_COMMON("readline",       0,                   "-lreadline",          "readline"),
	PYEXT_COMMON("pyexpat",        0,                   "-lexpat",             "pyexpat"),
	PYEXT_COMMON("zlib",           0,                   "-lz",                 "zlibmodule"),

	PYEXT_COMMON("_ctypes",0,"-lffi",
	             "_ctypes/_ctypes",
	             "_ctypes/callbacks",
	             "_ctypes/callproc",
	             "_ctypes/stgdict",
	             "_ctypes/cfield"),

	PYEXT_COMMON("_io",0,0,
	             "_io/bufferedio",
	             "_io/bytesio",
	             "_io/fileio",
	             "_io/iobase",
	             "_io/_iomodule",
	             "_io/stringio",
	             "_io/textio"),

	PYEXT_COMMON("_multiprocessing",0,0,
	             "_multiprocessing/multiprocessing",
	             "_multiprocessing/socket_connection",
	             "_multiprocessing/semaphore"),

	PYEXT_COMMON("_sqlite3",
	             "$(CFLAGS_SQLITE)",
	             "$(LDFLAGS_SQLITE)",
	             "_sqlite/cache",
	             "_sqlite/connection",
	             "_sqlite/cursor",
	             "_sqlite/microprotocols",
	             "_sqlite/module",
	             "_sqlite/prepare_protocol",
	             "_sqlite/row",
	             "_sqlite/statement",
	             "_sqlite/util"),

	PYEXT_COMMON("dbm",
	             "$(CFLAGS_DBM)",
	             "$(LDFLAGS_DBM)",
	             "dbmmodule"),

	PYEXT_ALTSTD("linuxaudiodev",
	             "-std=gnu99",
	             "linuxaudiodev"),

	{0,0,0,0,0,0},
};

static void pyext_uppercase(char * buf, const char * name)
{
	const char *	src;
	char *		dst;

	src = name;
	dst = buf;

	for (; *src; )
		*dst++ = ((*src >= 'a') && (*src <= 'z'))
			? 'A' - 'a' + *src++ : *src++;

	*dst = 0;
}

int main(int argc, char ** argv)
{
	const struct pyext_meta *	p;
	size_t				nlen;
	const char **			parg;
	const char *			dtab;
	const char *			otab;
	const char *			htab;
	const char *			stab;
	const char *			ltab;
	const char *			rtab;
	const char *			vtab;
	const char *			name;
	char				uname[64];

	if ((argc == 2) && !strcmp(argv[1],"--py-init-func")) {
		for (p=pyexts; p->name; p++)
			printf("PY_INIT_FUNC(init%s);\n",p->name);

		return 0;
	}

	if ((argc == 2) && !strcmp(argv[1],"--init-func-ptr")) {
		for (p=pyexts; p->name; p++) {
			nlen = strlen(p->name);

			if (nlen <= 3)
				dtab = "\t\t\t";

			else if (nlen <= 11)
				dtab = "\t\t";

			else
				dtab = "\t";

			if (nlen <= 9)
				rtab = "\t\t";

			else
				rtab = "\t";

			printf("\t{\"%s\",%sinit%s},%s\\\n",
				p->name,dtab,p->name,rtab);
		}

		return 0;
	}

	for (p=pyexts; p->name; p++) {
		/* init */
		name = (p->name[0] == '_') ? &p->name[1] : p->name;
		nlen = strlen(name);

		pyext_uppercase(uname,name);

		/* pretty */
		dtab = (nlen <= 4)
			? "\t\t\t"
			: (nlen <= 12)
				? "\t\t" : "\t";

		otab = (nlen <= 3)
			? "\t\t\t"
			: (nlen <= 11)
				? "\t\t" : "\t";

		ltab = (nlen <= 2)
			? "\t\t\t"
			: (nlen <= 10)
				? "\t\t" : "\t";

		rtab = (nlen <= 1)
			? "\t\t\t"
			: (nlen <= 9)
				? "\t\t" : "\t";

		vtab = (nlen <= 6)
			? "\t\t"
			: (nlen <= 14)
				? "\t" : "";

		htab = (nlen <= 8)
			? "\t\t" : "\t";

		stab = (nlen <= 9)
			? "\t\t" : "\t";


		/* output */
		printf("# %s\n",p->name);

		for (parg=p->srcs; *parg; parg++)
			printf("PYEXT_%s_SRCS%s+= "
				"pyext/obj/%s.c\n",
				uname,dtab,*parg);

		printf("\n");
		printf("PYEXT_%s_LOBJS%s= $(PYEXT_%s_SRCS:.c=.lo)\n",uname,otab,uname);
		printf("PYEXT_%s_OBJS%s= $(PYEXT_%s_SRCS:.c=.o)\n",uname,dtab,uname);
		printf("\n");

		for (parg=p->hdrs; parg && *parg; parg++)
			printf("$(PYEXT_%s_LOBJS):%s"
				"CFLAGS_CONFIG += %s\n",
				uname,htab,*parg);

		for (parg=p->hdrs; parg && *parg; parg++)
			printf("$(PYEXT_%s_OBJS):%s"
				"CFLAGS_CONFIG += %s\n",
				uname,stab,*parg);

		for (parg=p->cstd; parg && *parg; parg++)
				printf("$(PYEXT_%s_LOBJS):%s"
					"CFLAGS_LAST += %s\n",
					uname,otab,*parg);

		for (parg=p->cstd; parg && *parg; parg++)
			printf("$(PYEXT_%s_OBJS):%s"
				"CFLAGS_LAST += %s\n",
				uname,dtab,*parg);

		if (p->hdrs || p->cstd)
			printf("\n");

		printf("PYEXT_%s_SHARED%s= pyext/%s$(OS_LIB_SUFFIX)\n",uname,ltab,p->name);
		printf("PYEXT_%s_STATIC%s= pyext/%s$(OS_ARCHIVE_EXT)\n",uname,ltab,p->name);
		printf("\n");

		for (parg=p->vars; parg && *parg; parg++)
			printf("$(PYEXT_%s_SHARED):%s"
				"LDFLAGS_DYNEXT += %s\n",
				uname,vtab,*parg);

		for (parg=p->deps; parg && *parg; parg++)
			printf("$(PYEXT_%s_SHARED):%s%s\n",uname,vtab,*parg);

		printf("$(PYEXT_%s_SHARED):%s$(PYEXT_%s_LOBJS)\n",uname,vtab,uname);
		printf("$(PYEXT_%s_STATIC):%s$(PYEXT_%s_OBJS)\n",uname,vtab,uname);

		printf("\n");
		printf("pyext-%s-shared:%s$(PYEXT_%s_SHARED)\n",name,rtab,uname);
		printf("pyext-%s-static:%s$(PYEXT_%s_STATIC)\n",name,rtab,uname);

		printf("\n");
		printf("pyext-%s-clean:\n",name);
		printf("\trm -f $(PYEXT_%s_LOBJS)\n",uname);
		printf("\trm -f $(PYEXT_%s_OBJS)\n",uname);
		printf("\trm -f $(PYEXT_%s_SHARED)\n",uname);
		printf("\trm -f $(PYEXT_%s_STATIC)\n",uname);

		printf("\n");
		printf("clean:\tpyext-%s-clean\n",name);

		printf("\n");
		printf(".PHONY:\tpyext-%s-shared\n",name);
		printf(".PHONY:\tpyext-%s-static\n",name);
		printf(".PHONY:\tpyext-%s-clean\n",name);
		printf("\n\n");
	}

	return 0;
}