From f01b7cee1ace459f7b0cf64e965aefcefa9ac503 Mon Sep 17 00:00:00 2001 From: KirkMcDonald Date: Mon, 18 Dec 2006 11:00:22 +0000 Subject: [PATCH] PydMain; build improvements (no more colliding object files); examples and docs updated to use PydMain git-svn-id: http://svn.dsource.org/projects/pyd/trunk@64 1df65b71-e716-0410-9316-ac55df2b1602 --- dcompiler.py | 113 ++++++++++++++++------------ examples/hello/hello.d | 5 +- examples/inherit/inherit.d | 5 +- examples/testdll/testdll.d | 7 +- html_doc/basics.html | 15 ++-- html_doc/celerid.html | 3 +- html_doc/class_wrapping.html | 4 +- html_doc/func_wrapping.html | 5 +- html_doc/index.html | 10 +-- infrastructure/d/pydmain_template.d | 13 ++++ infrastructure/pyd/def.d | 5 +- raw_html/basics.html | 15 ++-- raw_html/celerid.html | 3 +- raw_html/class_wrapping.html | 4 +- raw_html/func_wrapping.html | 5 +- raw_html/index.html | 10 +-- support.py | 13 +++- 17 files changed, 130 insertions(+), 105 deletions(-) create mode 100644 infrastructure/d/pydmain_template.d diff --git a/dcompiler.py b/dcompiler.py index c871dc7..e677ab8 100644 --- a/dcompiler.py +++ b/dcompiler.py @@ -141,7 +141,20 @@ def compile(self, sources, outputOpts = self._outputOpts includePathOpts = [] - + + # All object files will be placed in one of three directories: + # infra - All of the infrastructure's object files. + # project - The project's own object files. + # outside - Any source files specified by the project which are not + # contained in the project's own directory. + orig_sources = sources + sources = [] + for source in orig_sources: + if os.path.abspath(source).startswith(os.getcwd()): + sources.append((source, 'project')) + else: + sources.append((source, 'outside')) + # To sources, add the appropriate D header file python.d, as well as # any platform-specific boilerplate. pythonHeaderPath = os.path.join(_infraDir, 'python', _pyVerXDotY, 'python.d') @@ -152,14 +165,14 @@ def compile(self, sources, raise DistutilsPlatformError('Required D translation of Python' ' header files "%s" is missing.' % pythonHeaderPath ) - sources.append(pythonHeaderPath) + sources.append((pythonHeaderPath, 'infra')) - # flags = (with_pyd, with_st, with_meta) - flags = [f for f, category in macros if category == 'aux'][0] + # flags = (with_pyd, with_st, with_meta, with_main) + with_pyd, with_st, with_meta, with_main = [f for f, category in macros if category == 'aux'][0] # And Pyd! - if flags[0]: + if with_pyd: # If we're not using StackThreads, don't use iteration.d in Pyd - if not flags[1] or not self._st_support: + if not with_st or not self._st_support: _pydFiles.remove('iteration.d'); for file in _pydFiles: filePath = os.path.join(_infraDir, 'pyd', file) @@ -167,29 +180,48 @@ def compile(self, sources, raise DistutilsPlatformError("Required Pyd source file '%s' is" " missing." % filePath ) - sources.append(filePath) + sources.append((filePath, 'infra')) + # If using PydMain, parse the template file + if with_main: + name = [n for n, category in macros if category == 'name'][0] + mainTemplatePath = os.path.join(_infraDir, 'd', 'pydmain_template.d') + if not os.path.isfile(mainTemplatePath): + raise DistutilsPlatformError( + "Required supporting code file %s is missing." % mainTemplatePath + ) + mainTemplate = open(mainTemplatePath).read() + mainFileContent = mainTemplate % {'modulename' : name} + # Store the finished pydmain.d file alongside the object files + infra_output_dir = os.path.join(output_dir, 'infra') + if not os.path.exists(infra_output_dir): + os.path.makedirs(infra_output_dir) + mainFilename = os.path.join(infra_output_dir, 'pydmain.d') + mainFile = open(mainFilename, 'w') + mainFile.write(mainFileContent) + mainFile.close() + sources.append((mainFilename, 'infra')) # And StackThreads - if self._st_support and flags[1]: + if self._st_support and with_st: for file in _stFiles: filePath = os.path.join(_infraDir, 'st', file) if not os.path.isfile(filePath): raise DistutilsPlatformError("Required StackThreads source" " file '%s' is missing." % filePath ) - sources.append(filePath) + sources.append((filePath, 'infra')) # Add the version conditional for st macros.append(('Pyd_with_StackThreads', 'version')) # And meta - if flags[2]: + if with_meta: for file in _metaFiles: filePath = os.path.join(_infraDir, 'meta', file) if not os.path.isfile(filePath): raise DistutilsPlatformError("Required meta source file" " '%s' is missing." % filePath ) - sources.append(filePath) + sources.append((filePath, 'infra')) # Add the infraDir to the include path for pyd, st, and meta. - if True in flags: + if True in (with_pyd, with_st, with_meta): includePathOpts += self._includeOpts includePathOpts[-1] = includePathOpts[-1] % os.path.join(_infraDir) @@ -206,7 +238,7 @@ def compile(self, sources, raise DistutilsFileError('Required supporting code file "%s"' ' is missing.' % boilerplatePath ) - sources.append(boilerplatePath) + sources.append((boilerplatePath, 'infra')) # Extension subclass DExtension will have packed any user-supplied # version and debug flags into macros; we extract them and convert them @@ -238,49 +270,34 @@ def compile(self, sources, else: optimizationOpts = self._defaultOptimizeOpts - print 'sources: ', [os.path.basename(s) for s in sources] - # Compiling one-by-one exhibits a strange bug in the D front-end, while - # compiling all at once works. This flags allows me to test each form - # easily. Supporting the one-by-one form is synonymous with GDC support. - ONE_BY_ONE = True - if ONE_BY_ONE: - for source in sources: - outOpts = outputOpts[:] - objName = self.object_filenames([os.path.split(source)[1]], 0, output_dir)[0] - outOpts[-1] = outOpts[-1] % _qp(objName) - cmdElements = ( - [binpath] + extra_preargs + compileOpts + - [pythonVersionOpt, self._unicodeOpt] + optimizationOpts + - includePathOpts + outOpts + userVersionAndDebugOpts + - [_qp(source)] + extra_postargs - ) - cmdElements = [el for el in cmdElements if el] - try: - self.spawn(cmdElements) - except DistutilsExecError, msg: - raise CompileError(msg) - else: - # gdc/gcc doesn't support the idea of an output directory, so we - # compile from the destination - sources = [_qp(os.path.abspath(s)) for s in sources] - cwd = os.getcwd() - os.chdir(output_dir) + print 'sources: ', [os.path.basename(s) for s, t in sources] + + objFiles = [] + for source, source_type in sources: + outOpts = outputOpts[:] + objFilename = os.path.splitext(source)[0] + self.obj_extension + if source_type == 'project': + objName = os.path.join(output_dir, 'project', objFilename) + elif source_type == 'outside': + objName = os.path.join(output_dir, 'outside', os.path.basename(objFilename)) + else: # infra + objName = os.path.join(output_dir, 'infra', os.path.basename(objFilename)) + if not os.path.exists(os.path.dirname(objName)): + os.makedirs(os.path.dirname(objName)) + objFiles.append(objName) + outOpts[-1] = outOpts[-1] % _qp(objName) cmdElements = ( [binpath] + extra_preargs + compileOpts + [pythonVersionOpt, self._unicodeOpt] + optimizationOpts + - includePathOpts + userVersionAndDebugOpts + - sources + extra_postargs + includePathOpts + outOpts + userVersionAndDebugOpts + + [_qp(source)] + extra_postargs ) cmdElements = [el for el in cmdElements if el] - try: self.spawn(cmdElements) except DistutilsExecError, msg: - #os.chdir(cwd) raise CompileError(msg) - os.chdir(cwd) - - return [os.path.join(output_dir, fn) for fn in os.listdir(output_dir) if fn.endswith(self.obj_extension)] + return objFiles def link (self, target_desc, objects, output_filename, @@ -431,7 +448,7 @@ def _def_file(self, output_dir, output_filename): f.close() defFileContents = defTemplate % os.path.basename(output_filename) - defFilePath = os.path.join(output_dir, 'python_dll_def.def') + defFilePath = os.path.join(output_dir, 'infra', 'python_dll_def.def') f = file(defFilePath, 'wb') try: f.write(defFileContents) diff --git a/examples/hello/hello.d b/examples/hello/hello.d index bacbded..4c21e9c 100644 --- a/examples/hello/hello.d +++ b/examples/hello/hello.d @@ -8,8 +8,7 @@ void hello() { writefln("Hello, world!"); } -extern(C) -export void inithello() { +extern(C) void PydMain() { def!(hello); - module_init("hello"); + module_init(); } diff --git a/examples/inherit/inherit.d b/examples/inherit/inherit.d index a9e9d9a..30b0a15 100644 --- a/examples/inherit/inherit.d +++ b/examples/inherit/inherit.d @@ -30,11 +30,10 @@ void call_poly(Base b) { b.foo(); } -extern(C) -export void initinherit() { +extern(C) void PydMain() { def!(call_poly); - module_init("inherit"); + module_init(); wrapped_class!(Base) b; b.def!(Base.foo); diff --git a/examples/testdll/testdll.d b/examples/testdll/testdll.d index 9907202..4f29023 100644 --- a/examples/testdll/testdll.d +++ b/examples/testdll/testdll.d @@ -127,8 +127,9 @@ void throws() { throw new Exception("Yay! An exception!"); } -extern (C) -export void inittestdll() { +//extern (C) +//export void inittestdll() { +extern(C) void PydMain() { def!(foo); // Python does not support function overloading. This allows us to wrap // an overloading function under a different name. Note that if the @@ -144,7 +145,7 @@ export void inittestdll() { def!(dg_test); def!(throws); - module_init("testdll"); + module_init(); wrapped_class!(Foo) f; // Constructor wrapping diff --git a/html_doc/basics.html b/html_doc/basics.html index fdc580e..d06787b 100644 --- a/html_doc/basics.html +++ b/html_doc/basics.html @@ -33,9 +33,8 @@

Module basics

import pyd.pyd;
 
-extern (C)
-export void inittestmodule() {
-    module_init("testmodule");
+extern (C) void PydMain() {
+    module_init();
 }

The first line imports Pyd:

@@ -44,17 +43,15 @@

Module basics

The pyd module in the pyd package publicly imports all of the other components of Pyd.

-

The "init" function is a requirement of the Python/C API. It is a global function with the footprint extern(C) export void function(). Its name must be init plus the name of your module. This function must then contain a call to module_init, with the same module name as an argument. (Users of Boost.Python will be familiar with the BOOST_PYTHON_MODULE macro used in that library. Unfortunately for this purpose, D has no preprocessor, and cannot define the name of a function like the C preprocessor can. Therefore, users of Pyd must define their init functions manually.)

+

The PydMain function is called when the module is imported by Python. You will call most of Pyd's API from here. At the very least, PydMain must contain a call to module_init. The module_init function has the following form:

-

The module_init function has the following form:

- -

PyObject* module_init(char[] name, char[] docstring="");

+

PyObject* module_init(char[] docstring="");

It does little more than call Py_InitModule and return the new module object. This object is also available via the Pyd_Module_p property once you've called module_init.

-

Due to the way in which Pyd implements function and class wrapping, any calls to def must occur before the call to module_init, and any calls to finalize_class must occur after the call. I know this seems like a rather arbitrary rule, but it is important. Calls to def in the wrong place will simply be ignored, and calls to finalize_class in the wrong place will throw an assert. (And this assert will cause the Python interpreter to crash. So be warned.)

+

Due to the way in which Pyd implements function and class wrapping, any calls to def must occur before the call to module_init, and any calls to finalize_class must occur after the call. I know this seems like a rather arbitrary rule, but it is important. Calls to def in the wrong place will simply be ignored, and calls to finalize_class in the wrong place will throw an assert.

-

It is important that no D exceptions escape from the init function. If you put any of your own code in the init function, be sure to guard it aginst exceptions. The exception wrapping facilities of Pyd provide some useful functions for this purpose.

+

PydMain will catch any D exception that is thrown from inside it, and safely pass that exception to Python.

diff --git a/html_doc/celerid.html b/html_doc/celerid.html index 984dc67..06cb7e9 100644 --- a/html_doc/celerid.html +++ b/html_doc/celerid.html @@ -54,10 +54,11 @@

CeleriD

version_flags
This should be a list of strings, which will be passed to the D compiler as version flags.
debug_flags
Similar to version_flags, the strings in this list will be passed to D as debug flags.
-
raw_only
This flag defaults to False. When True, it supresses the compilation and linkage of Pyd, StackThreads, and meta. This is useful if you only want to write a raw Python/C extension without the overhead of Pyd and its auxiliary packages. This is equivalent to specifying False to the next three flags.
+
raw_only
This flag defaults to False. When True, it supresses the compilation and linkage of Pyd, StackThreads, and meta. This is useful if you only want to write a raw Python/C extension without the overhead of Pyd and its auxiliary packages. This is equivalent to specifying False to the next four flags.
with_pyd
This flag defaults to True. When False, it supresses the compilation and linkage of Pyd. This is useful if you want to write a raw Python/C extension and don't want the overhead of compiling Pyd.
with_st
This flag defaults to True. When False, it supresses the compilation and linkage of StackThreads. Pyd uses StackThreads for its iteration wrapping support. By setting this to False, opApply wrapping, wrapped_class.iter, and wrapped_class.alt_iter will be unavailable. If with_pyd and this are True, then the Pyd_with_StackThreads version flag will be defined (which is used internally by Pyd). Important note: StackThreads does not currently work with GDC! CeleriD will always set this flag to False when using GDC! This means that opApply wrapping is not available on Linux at this time.
with_meta
This flag defaults to True. When False, it supresses the compilation and linkage of meta (Pyd's metaprogramming package). Because Pyd depends on meta, an exception will be raised if with_pyd is True and this is not.
+
with_main
This flag defaults to True. When False, it supresses the use of the "magic" PydMain function. (Instead, users must manually declare a C-style init function.) Do not use this unless you know what you are doing. If with_pyd is False, this will silently be set to False as well. PydMain can only be used if Pyd itself is in use.
diff --git a/html_doc/class_wrapping.html b/html_doc/class_wrapping.html index a2b7197..e4b8cac 100644 --- a/html_doc/class_wrapping.html +++ b/html_doc/class_wrapping.html @@ -120,7 +120,7 @@

Inheritance

void foo() { writefln("Derived.foo"); } } -

These would be exposed to Python by putting this code in out init function after the call to module_init:

+

These would be exposed to Python by putting this code in PydMain after the call to module_init:

wrapped_class!(Base) b;
 b.def!(Base.foo);
@@ -225,7 +225,7 @@ 

Examples

} }
-

We would expose this class to Python by putting this code in our init function after the call to module_init:

+

We would expose this class to Python by putting this code in PydMain after the call to module_init:

// Make an instance of wrapped_class
 wrapped_class!(Foo) f;
diff --git a/html_doc/func_wrapping.html b/html_doc/func_wrapping.html
index 5610da8..4557282 100644
--- a/html_doc/func_wrapping.html
+++ b/html_doc/func_wrapping.html
@@ -59,8 +59,7 @@ 

Function wrapping

writefln("i = %s\ns = %s", i, s); } -extern (C) -export void inittestmodule() { +extern (C) void PydMain() { // Plain old function def!(foo); // Wraps the lexically first function under the given name @@ -70,7 +69,7 @@

Function wrapping

// Wraps the function with default arguments def!(baz); - module_init("testmodule"); + module_init(); }

And when used in Python:

diff --git a/html_doc/index.html b/html_doc/index.html index 7edbf4a..f955ff7 100644 --- a/html_doc/index.html +++ b/html_doc/index.html @@ -32,10 +32,6 @@

Pyd

Pyd includes the meta.Nameof package by Don Clugston. The source files meta.Nameof and meta.Demangle are copyright © 2005-2006 Don Clugston.

- -

Pyd's Trac page can be found here.

A simple "hello, world" module might look like this:

@@ -47,11 +43,9 @@

Pyd

writefln("Hello, world!"); } -extern (C) -export void inittestdll() { +extern (C) void PydMain() { def!(hello_func); - - module_init("testdll"); + module_init(); }

When compiled, the module can be loaded and used from Python like any other module:

diff --git a/infrastructure/d/pydmain_template.d b/infrastructure/d/pydmain_template.d new file mode 100644 index 0000000..3570953 --- /dev/null +++ b/infrastructure/d/pydmain_template.d @@ -0,0 +1,13 @@ +import pyd.def; +import pyd.exception; + +extern(C) void PydMain(); + +extern(C) +export void init%(modulename)s() { + pyd.exception.exception_catcher(delegate void() { + pyd.def.pyd_module_name = "%(modulename)s"; + PydMain(); + }); +} + diff --git a/infrastructure/pyd/def.d b/infrastructure/pyd/def.d index 5cd65c6..6196d17 100644 --- a/infrastructure/pyd/def.d +++ b/infrastructure/pyd/def.d @@ -98,11 +98,14 @@ void def(char[] modulename, alias fn, char[] name = symbolnameof!(fn), fn_t=type (*list) ~= empty; } +char[] pyd_module_name; + /** * Module initialization function. Should be called after the last call to def. */ -PyObject* module_init(char[] name, char[] docstring="") { +PyObject* module_init(char[] docstring="") { //_loadPythonSupport(); + char[] name = pyd_module_name; ready_module_methods(""); pyd_modules[""] = Py_InitModule3((name ~ \0).ptr, module_methods[""].ptr, (docstring ~ \0).ptr); return pyd_modules[""]; diff --git a/raw_html/basics.html b/raw_html/basics.html index 250195e..3ee19e9 100644 --- a/raw_html/basics.html +++ b/raw_html/basics.html @@ -18,9 +18,8 @@

Module basics

import pyd.pyd;
 
-extern (C)
-export void inittestmodule() {
-    module_init("testmodule");
+extern (C) void PydMain() {
+    module_init();
 }

The first line imports Pyd:

@@ -29,17 +28,15 @@

Module basics

The pyd module in the pyd package publicly imports all of the other components of Pyd.

-

The "init" function is a requirement of the Python/C API. It is a global function with the footprint extern(C) export void function(). Its name must be init plus the name of your module. This function must then contain a call to module_init, with the same module name as an argument. (Users of Boost.Python will be familiar with the BOOST_PYTHON_MODULE macro used in that library. Unfortunately for this purpose, D has no preprocessor, and cannot define the name of a function like the C preprocessor can. Therefore, users of Pyd must define their init functions manually.)

+

The PydMain function is called when the module is imported by Python. You will call most of Pyd's API from here. At the very least, PydMain must contain a call to module_init. The module_init function has the following form:

-

The module_init function has the following form:

- -

PyObject* module_init(char[] name, char[] docstring="");

+

PyObject* module_init(char[] docstring="");

It does little more than call Py_InitModule and return the new module object. This object is also available via the Pyd_Module_p property once you've called module_init.

-

Due to the way in which Pyd implements function and class wrapping, any calls to def must occur before the call to module_init, and any calls to finalize_class must occur after the call. I know this seems like a rather arbitrary rule, but it is important. Calls to def in the wrong place will simply be ignored, and calls to finalize_class in the wrong place will throw an assert. (And this assert will cause the Python interpreter to crash. So be warned.)

+

Due to the way in which Pyd implements function and class wrapping, any calls to def must occur before the call to module_init, and any calls to finalize_class must occur after the call. I know this seems like a rather arbitrary rule, but it is important. Calls to def in the wrong place will simply be ignored, and calls to finalize_class in the wrong place will throw an assert.

-

It is important that no D exceptions escape from the init function. If you put any of your own code in the init function, be sure to guard it aginst exceptions. The exception wrapping facilities of Pyd provide some useful functions for this purpose.

+

PydMain will catch any D exception that is thrown from inside it, and safely pass that exception to Python.

diff --git a/raw_html/celerid.html b/raw_html/celerid.html index 0cee9b6..d1004dd 100644 --- a/raw_html/celerid.html +++ b/raw_html/celerid.html @@ -39,10 +39,11 @@

CeleriD

version_flags
This should be a list of strings, which will be passed to the D compiler as version flags.
debug_flags
Similar to version_flags, the strings in this list will be passed to D as debug flags.
-
raw_only
This flag defaults to False. When True, it supresses the compilation and linkage of Pyd, StackThreads, and meta. This is useful if you only want to write a raw Python/C extension without the overhead of Pyd and its auxiliary packages. This is equivalent to specifying False to the next three flags.
+
raw_only
This flag defaults to False. When True, it supresses the compilation and linkage of Pyd, StackThreads, and meta. This is useful if you only want to write a raw Python/C extension without the overhead of Pyd and its auxiliary packages. This is equivalent to specifying False to the next four flags.
with_pyd
This flag defaults to True. When False, it supresses the compilation and linkage of Pyd. This is useful if you want to write a raw Python/C extension and don't want the overhead of compiling Pyd.
with_st
This flag defaults to True. When False, it supresses the compilation and linkage of StackThreads. Pyd uses StackThreads for its iteration wrapping support. By setting this to False, opApply wrapping, wrapped_class.iter, and wrapped_class.alt_iter will be unavailable. If with_pyd and this are True, then the Pyd_with_StackThreads version flag will be defined (which is used internally by Pyd). Important note: StackThreads does not currently work with GDC! CeleriD will always set this flag to False when using GDC! This means that opApply wrapping is not available on Linux at this time.
with_meta
This flag defaults to True. When False, it supresses the compilation and linkage of meta (Pyd's metaprogramming package). Because Pyd depends on meta, an exception will be raised if with_pyd is True and this is not.
+
with_main
This flag defaults to True. When False, it supresses the use of the "magic" PydMain function. (Instead, users must manually declare a C-style init function.) Do not use this unless you know what you are doing. If with_pyd is False, this will silently be set to False as well. PydMain can only be used if Pyd itself is in use.
diff --git a/raw_html/class_wrapping.html b/raw_html/class_wrapping.html index c84318f..756b8e4 100644 --- a/raw_html/class_wrapping.html +++ b/raw_html/class_wrapping.html @@ -105,7 +105,7 @@

Inheritance

void foo() { writefln("Derived.foo"); } } -

These would be exposed to Python by putting this code in out init function after the call to module_init:

+

These would be exposed to Python by putting this code in PydMain after the call to module_init:

wrapped_class!(Base) b;
 b.def!(Base.foo);
@@ -210,7 +210,7 @@ 

Examples

} }
-

We would expose this class to Python by putting this code in our init function after the call to module_init:

+

We would expose this class to Python by putting this code in PydMain after the call to module_init:

// Make an instance of wrapped_class
 wrapped_class!(Foo) f;
diff --git a/raw_html/func_wrapping.html b/raw_html/func_wrapping.html
index f62a414..9643f27 100644
--- a/raw_html/func_wrapping.html
+++ b/raw_html/func_wrapping.html
@@ -44,8 +44,7 @@ 

Function wrapping

writefln("i = %%s\ns = %%s", i, s); } -extern (C) -export void inittestmodule() { +extern (C) void PydMain() { // Plain old function def!(foo); // Wraps the lexically first function under the given name @@ -55,7 +54,7 @@

Function wrapping

// Wraps the function with default arguments def!(baz); - module_init("testmodule"); + module_init(); }

And when used in Python:

diff --git a/raw_html/index.html b/raw_html/index.html index 293650f..95d6d69 100644 --- a/raw_html/index.html +++ b/raw_html/index.html @@ -17,10 +17,6 @@

Pyd

Pyd includes the meta.Nameof package by Don Clugston. The source files meta.Nameof and meta.Demangle are copyright © 2005-2006 Don Clugston.

- -

Pyd's Trac page can be found here.

A simple "hello, world" module might look like this:

@@ -32,11 +28,9 @@

Pyd

writefln("Hello, world!"); } -extern (C) -export void inittestdll() { +extern (C) void PydMain() { def!(hello_func); - - module_init("testdll"); + module_init(); }

When compiled, the module can be loaded and used from Python like any other module:

diff --git a/support.py b/support.py index 30cc377..7a13142 100644 --- a/support.py +++ b/support.py @@ -38,22 +38,33 @@ def __init__(self, *args, **kwargs): define_macros.append((flag, 'debug')) del kwargs['debug_flags'] + # Pass in the extension name so the compiler class can know it + if 'name' in kwargs: + define_macros.append((kwargs['name'], 'name')) + elif len(args) > 0: + define_macros.append((args[0], 'name')) + # Similarly, pass in no_pyd, &c, via define_macros. if 'raw_only' in kwargs: kwargs['with_pyd'] = False kwargs['with_st'] = False kwargs['with_meta'] = False + kwargs['with_main'] = False del kwargs['raw_only'] with_pyd = kwargs.pop('with_pyd', True) with_st = kwargs.pop('with_st', True) with_meta = kwargs.pop('with_meta', True) + with_main = kwargs.pop('with_main', True) if with_pyd and not with_meta: raise DistutilsOptionError( 'Cannot specify with_meta=False while using Pyd. Specify' ' raw_only=True or with_pyd=False if you want to compile a raw Python/C' ' extension.' ) - define_macros.append(((with_pyd, with_st, with_meta), 'aux')) + if with_main and not with_pyd: + # The special PydMain function should only be used when using Pyd + with_main = False + define_macros.append(((with_pyd, with_st, with_meta, with_main), 'aux')) kwargs['define_macros'] = define_macros std_Extension.__init__(self, *args, **kwargs)