[Py++] Export #define directives to ctypes
Hello, Is there a way to export preprocessor definitions (#define ...) with the ctypes code generator? At the moment I'm using this rather nasty hack: /* Header file */ // FUSE_SET_ATTR_* is defined with #define in fuse_lowlevel.h #include <fuse_lowlevel.h> const int D_FUSE_SET_ATTR_MODE = FUSE_SET_ATTR_MODE; const int D_FUSE_SET_ATTR_UID = FUSE_SET_ATTR_UID; // ... # Code generator mb.write_module(os.path.join(code_path, 'ctypes_api.py')) fh = open(os.path.join(code_path, 'ctypes_api.py'), 'a') fh.write('\n') for var in mb.global_ns.decls(lambda f: f.name.startswith('D_')): fh.write('{0} = {1}\n'.format(var.name[2:], var._value)) fh.close() But it'd be nice if there was a better solution (so that I don't have to define a new variable for every #define that I want to export). Best, -Nikolaus -- »Time flies like an arrow, fruit flies like a Banana.« PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C
On Mon, Dec 28, 2009 at 12:54 AM, Nikolaus Rath <Nikolaus@rath.org> wrote:
Hello,
Is there a way to export preprocessor definitions (#define ...) with the ctypes code generator?
At the moment I'm using this rather nasty hack:
/* Header file */ // FUSE_SET_ATTR_* is defined with #define in fuse_lowlevel.h #include <fuse_lowlevel.h> const int D_FUSE_SET_ATTR_MODE = FUSE_SET_ATTR_MODE; const int D_FUSE_SET_ATTR_UID = FUSE_SET_ATTR_UID; // ...
# Code generator mb.write_module(os.path.join(code_path, 'ctypes_api.py')) fh = open(os.path.join(code_path, 'ctypes_api.py'), 'a') fh.write('\n') for var in mb.global_ns.decls(lambda f: f.name.startswith('D_')): fh.write('{0} = {1}\n'.format(var.name[2:], var._value)) fh.close()
But it'd be nice if there was a better solution (so that I don't have to define a new variable for every #define that I want to export).
ctypes code generator is missing an important future to make it work - adding user code. I will try to implement it pretty soon. Let me explain. mb = ctypes_module_builder_t( ... ) for file_path in pygccxml.declarations.declaration_files( mb.global_ns ): if file_path is not under "fuse" source code directory: continue else: use simple regex to search for "#define FUSE_*" expression, extract its value and add it to mb. Does this solution makes sense to you? If so, I will take a look on it this evening. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/
Roman Yakovenko <roman.yakovenko@gmail.com> writes:
On Mon, Dec 28, 2009 at 12:54 AM, Nikolaus Rath <Nikolaus@rath.org> wrote:
Hello,
Is there a way to export preprocessor definitions (#define ...) with the ctypes code generator?
At the moment I'm using this rather nasty hack:
/* Header file */ // FUSE_SET_ATTR_* is defined with #define in fuse_lowlevel.h #include <fuse_lowlevel.h> const int D_FUSE_SET_ATTR_MODE = FUSE_SET_ATTR_MODE; const int D_FUSE_SET_ATTR_UID = FUSE_SET_ATTR_UID; // ...
# Code generator mb.write_module(os.path.join(code_path, 'ctypes_api.py')) fh = open(os.path.join(code_path, 'ctypes_api.py'), 'a') fh.write('\n') for var in mb.global_ns.decls(lambda f: f.name.startswith('D_')): fh.write('{0} = {1}\n'.format(var.name[2:], var._value)) fh.close()
But it'd be nice if there was a better solution (so that I don't have to define a new variable for every #define that I want to export).
ctypes code generator is missing an important future to make it work - adding user code. I will try to implement it pretty soon.
Let me explain.
mb = ctypes_module_builder_t( ... ) for file_path in pygccxml.declarations.declaration_files( mb.global_ns ): if file_path is not under "fuse" source code directory: continue else: use simple regex to search for "#define FUSE_*" expression, extract its value and add it to mb.
Does this solution makes sense to you?
Not quite. I'd rather have the "use simple regex to search for "#define FUSE_*" expression" part in Py++ rather than in my own code. Also, I'm not sure if a simple regex is really a good solution for this. The following will probably fail already (i.e., give the value of FUSE_FOO as the string 'FUSE_BLA' rather than the number 42): #define FUSE_BLA 42 #define FUSE_FOO FUSE_BLA Best, -Nikolaus -- »Time flies like an arrow, fruit flies like a Banana.« PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C
On Mon, Dec 28, 2009 at 5:57 PM, Nikolaus Rath <Nikolaus@rath.org> wrote:
Not quite. I'd rather have the "use simple regex to search for "#define FUSE_*" expression" part in Py++ rather than in my own code.
It is definitely possible, if we will agree on a desired/sufficient functionality.
Also, I'm not sure if a simple regex is really a good solution for this. The following will probably fail already (i.e., give the value of FUSE_FOO as the string 'FUSE_BLA' rather than the number 42):
#define FUSE_BLA 42 #define FUSE_FOO FUSE_BLA
It will fall on many other cases too, but lets take a look on your use case: grep -nHIr -- FUSE_.* (in directory: /usr/include/fuse) grep -nHIr -- FUSE_.* (in directory: /usr/include/fuse) ./fuse_compat.h:193:#define FUSE_DEBUG_COMPAT1 (1 << 1) ./fuse.h:9:#ifndef _FUSE_H_ ./fuse.h:10:#define _FUSE_H_ ./fuse.h:16: * IMPORTANT: you should define FUSE_USE_VERSION before including this ./fuse.h:22:#ifndef FUSE_USE_VERSION ./fuse.h:23:#define FUSE_USE_VERSION 21 ./fuse.h:678: * Filesystem modules are registered with the FUSE_REGISTER_MODULE() ./fuse.h:716: * This function is used by FUSE_REGISTER_MODULE and there's usually ./fuse.h:727:#define FUSE_REGISTER_MODULE(name_, factory_) \ ./fuse.h:779:#if FUSE_USE_VERSION < 26 ./fuse.h:782:# if FUSE_USE_VERSION == 25 ./fuse.h:789:# elif FUSE_USE_VERSION == 22 ./fuse.h:797:# elif FUSE_USE_VERSION == 24 ./fuse.h:804:# if FUSE_USE_VERSION == 21 ./fuse.h:817:# define FUSE_DEBUG FUSE_DEBUG_COMPAT1 ./fuse.h:826:#endif /* _FUSE_H_ */ ./fuse_common.h:11:#if !defined(_FUSE_H_) && !defined(_FUSE_LOWLEVEL_H_) ./fuse_common.h:15:#ifndef _FUSE_COMMON_H_ ./fuse_common.h:16:#define _FUSE_COMMON_H_ ./fuse_common.h:22:#define FUSE_MAJOR_VERSION 2 ./fuse_common.h:25:#define FUSE_MINOR_VERSION 7 ./fuse_common.h:27:#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) ./fuse_common.h:28:#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) ./fuse_common.h:209:#if FUSE_USE_VERSION < 26 ./fuse_common.h:211:# if FUSE_USE_VERSION < 25 ./fuse_common.h:216:# undef FUSE_MINOR_VERSION ./fuse_common.h:219:# if FUSE_USE_VERSION == 25 ./fuse_common.h:220:# define FUSE_MINOR_VERSION 5 ./fuse_common.h:222:# elif FUSE_USE_VERSION == 24 || FUSE_USE_VERSION == 22 ./fuse_common.h:223:# define FUSE_MINOR_VERSION 4 ./fuse_common.h:225:# elif FUSE_USE_VERSION == 21 ./fuse_common.h:226:# define FUSE_MINOR_VERSION 1 ./fuse_common.h:228:# elif FUSE_USE_VERSION == 11 ./fuse_common.h:230:# undef FUSE_MAJOR_VERSION ./fuse_common.h:231:# define FUSE_MAJOR_VERSION 1 ./fuse_common.h:232:# define FUSE_MINOR_VERSION 1 ./fuse_common.h:243:#endif /* _FUSE_COMMON_H_ */ ./fuse_lowlevel.h:9:#ifndef _FUSE_LOWLEVEL_H_ ./fuse_lowlevel.h:10:#define _FUSE_LOWLEVEL_H_ ./fuse_lowlevel.h:16: * IMPORTANT: you should define FUSE_USE_VERSION before including this ./fuse_lowlevel.h:22:#ifndef FUSE_USE_VERSION ./fuse_lowlevel.h:23:#define FUSE_USE_VERSION 24 ./fuse_lowlevel.h:44:#define FUSE_ROOT_ID 1 ./fuse_lowlevel.h:115:#define FUSE_SET_ATTR_MODE (1 << 0) ./fuse_lowlevel.h:116:#define FUSE_SET_ATTR_UID (1 << 1) ./fuse_lowlevel.h:117:#define FUSE_SET_ATTR_GID (1 << 2) ./fuse_lowlevel.h:118:#define FUSE_SET_ATTR_SIZE (1 << 3) ./fuse_lowlevel.h:119:#define FUSE_SET_ATTR_ATIME (1 << 4) ./fuse_lowlevel.h:120:#define FUSE_SET_ATTR_MTIME (1 << 5) ./fuse_lowlevel.h:1367:#if FUSE_USE_VERSION < 26 ./fuse_lowlevel.h:1371:# if FUSE_USE_VERSION == 25 ./fuse_lowlevel.h:1374:# elif FUSE_USE_VERSION == 24 ./fuse_lowlevel.h:1389:#endif /* _FUSE_LOWLEVEL_H_ */ ./fuse_opt.h:9:#ifndef _FUSE_OPT_H_ ./fuse_opt.h:10:#define _FUSE_OPT_H_ ./fuse_opt.h:97:#define FUSE_OPT_KEY(templ, key) { templ, -1U, key } ./fuse_opt.h:103:#define FUSE_OPT_END { .templ = NULL } ./fuse_opt.h:122:#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 } ./fuse_opt.h:128:#define FUSE_OPT_KEY_OPT -1 ./fuse_opt.h:136:#define FUSE_OPT_KEY_NONOPT -2 ./fuse_opt.h:144:#define FUSE_OPT_KEY_KEEP -3 ./fuse_opt.h:152:#define FUSE_OPT_KEY_DISCARD -4 ./fuse_opt.h:261:#endif /* _FUSE_OPT_H_ */ Search completed with 63 matches. I could be wrong, but a proposed solution successfully handles ( more-or-less ) 70% of use cases. It is not that bad. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/
Hi Nikolaus. The ability to inject user code was added. The relevant commit is: http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1792&view=rev The usage is pretty simple: mb = ctypes_module_builder_t( ... ) #will add code to the top of the module mb.add_module_code( "#top", tail=False ) #will add code to the bottom of the module mb.add_module_code( "#bottom", tail=True ) Even if it doesn't solve you the current issue, it can help you with PyLint. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/
participants (2)
-
Nikolaus Rath -
Roman Yakovenko