GNOME Bugzilla – Bug 695235
nil is a keyword in Objective-C++
Last modified: 2016-03-03 12:05:34 UTC
struct nil is defined in sigc++/functors/functor_trait.h. That's a problem when libsigc++ is used with Objective-C++ programs, because nil is a keyword in Objective-C++. Régis Duchesne made an attempt to fix this problem 7 years ago with commit https://git.gnome.org/browse/libsigc++2/commit/?id=9d769959df0957bf3329d97de623f8f62713d2b1 That commit proved to break ABI, and it was soon reverted, https://git.gnome.org/browse/libsigc++2/commit/?id=33547a7fd18c5e9bc1ae0e9b7f8b157f761a608f I think there is another way to fix this problem without breaking ABI. I'll make a patch that can be tested. Whether it does or does not work out well, nil should be changed to something else when we can break ABI. ---------------- From an email conversation with Régis Duchesne: ("> " text written by Kjell, other text written by Régis) > I think it can be fixed without breaking ABI for every user of libsigc++. > > In the header files where nil exists: > > #ifdef SIGC_NIL_IS_A_KEYWORD > #define nil sigc_nil > #endif > <<< almost all of the present header file >>> > #ifdef SIGC_NIL_IS_A_KEYWORD > #undef nil > #endif > > SIGC_NIL_IS_A_KEYWORD can be defined or not defined in sigc++config.h, > depending either on a configure-time check, or on a preprocessor constant > that unambiguously identifies an Objective-C++ compiler, if there is such a > constant. My change at https://git.gnome.org/browse/libsigc++2/commit/?id=9d769959df0957bf3329d97de623f8f62713d2b1 did that: it used the preprocessor constant __OBJC__ to unambiguously identify an Objective-C (or Objective-C++) compiler. But your change is slightly different and might actually work (as long as an Objective C++ compiler is NOT used to compile gtkmm, but why would you do that, you should use a regular C++ compiler to compile libsigc++, glibmm, gtkmm...) > Will you file a bug? If you won't, I can do it. In either case, I will need > help from someone with an Objective-C++ compiler for testing a fix. I would prefer if you file the bug, but I would be happy to help you test a fix with an Objective-C++ compiler. -------------- Added after the email conversation: I browsed the gcc documentation and realized that it can compile Objective- C++ programs. Previously I misunderstood, I think. gcc invokes a compiler depending on the suffix of the compiled file. The .cc files in libsigc++ will be compiled by the C++ compiler with __OBJC__ undefined. A .m file in an application program will be compiled by the Objective-C compiler, and a .M file by the Objective-C++ compiler, in both cases with __OBJC__ defined. A configure-time check is not useful. C++ files will be compiled with struct nil defined, Objective-C++ files with struct nil replaced by struct sigc_nil. Might cause problems! Let's see if it works well enough. Luckily libsigc++ consists mostly of template classes and template functions in header files. There is no 'nil' in any name in the libsigc-2.0.so file. Checked with "nm libsigc-2.0.so | grep nil". There may still be problems if the application program consists of a mixture of Objective-C[++] and C[++] files. If so, the application can define SIGC_NIL_IS_A_KEYWORD in the C and C++ files. But not even that trick will do if the application program also depends on glibmm or gtkmm. Both libgiomm-2.4.so, libglibmm-2.4.so, libgdkmm-3.0.so, and libgtkmm-3.0.so contain 'nil'. If I get a small Objective-C[++] test program or two, I can do some of the testing myself.
I've made some changes to libsigc++. Now I need a small Objective-C++ test case. I hope that I can fix this bug without learning Objective-C++. I made a test case by just renaming libsigc++2/tests/test_bind.cc to test_bind.M. That didn't work, or rather it worked too well. It compiled and run even without my changes to the header files. I need a test case that does not compile due to illegal use of the keyword nil in libsigc++'s header files. Régis, do you prefer to do all the testing with Objective-C++ yourself? Is all the code you've got proprietary code that you're not allowed to attach to this bug?
Created attachment 238760 [details] [review] patch: Make it easier to use libsigc++ with Objective-C++. I've noticed that if I add #include <objc/objc.h> to test_bind.M before other #include directives, then compilation fails both with and without my first set of changes of libsigc++. objc.h contains typedef struct objc_object { Class class_pointer; } *id; #define nil (id)0 What kind of keyword is nil? I thought keywords were built into the compiler. This is a preprocessor definition. It would clash with any "#define nil ..." in libsigc++. The patch contains a slightly different modification of libsigc++. It does not break ABI when libsigc++ is used in a normal C++ program. If SIGC_DONT_DECLARE_NIL is defined, the patched libsigc++ can be used in a program that contains #include <objc/objc.h>, but then it breaks ABI. The patch ought to be tested on some real Objective-C++ programs.
Created attachment 239367 [details] [review] patch: Make it easier to use libsigc++ with Objective-C++. Here's another patch. SIGC_DONT_DECLARE_NIL is not defined automatically when an Objective-C++ program is compiled. The definition must be added either in the source code before the #include directives, or as a compiler option. I'm afraid we can break some programs, if SIGC_DONT_DECLARE_NIL is defined automatically. I feel more at ease if it's only defined manually.
I'm waiting for someone who uses Objective-C++ to test the patch. I don't want to push it unless it's tested with Objective-C++ and found useful. The patch does not apply to HEAD in git's master branch after my latest commit. I can update the patch, but I'll wait until someone is ready to start testing.
Created attachment 246686 [details] [review] patch: Make it easier to use libsigc++ with Objective-C++. An updated patch. SIGC_DONT_DECLARE_NIL has been renamed to SIGC_DONT_DECLARE_STRUCT_NIL. If it's not defined, #undef nil. Inspired by a post on libsigc-list https://mail.gnome.org/archives/libsigc-list/2013-June/msg00001.html If no user of Objective-C++ is willing to test my patch, and finds it useful, I'll just keep it here in Bugzilla as a reminder that struct nil shall be renamed at the next ABI break.
Created attachment 290480 [details] [review] patch: Make it easier to use libsigc++ with Objective-C++. Yet another patch. This one contains a configuration-time check for the non-standard preprocessor directives #pragma push_macro("name") #pragma pop_macro("name") g++, clang++ and MS Visual C++ support these directives. If nil is defined, and the preprocessor directives are supported, they are used for temporarily undefining nil in the header files where nil is used. This is a better solution, provided you use a preprocessor that suports push_macro()/pop_macro(). Still the long-term solution, when we can break ABI, will be to change the name 'nil' in libsigc++. I'm still waiting for comments from someone who uses libsigc++ in combination with Objective-C++.
I think I hit this bug when trying to compile ardor 4.4 with libsigc++ 2.6.2 (from homebrew). compilation fails with: /usr/local/Cellar/libsigc++/2.6.2/include/sigc++-2.0/sigc++/functors/functor_trait.h:18:1: error: declaration of anonymous struct must be a definition see https://gist.githubusercontent.com/david0/3c66848654c44048bf8d/raw/ffac06eac19112941bcbd356c692a48381502c1b/compile.log a full log. I tried the newer patch (290480), but it didnt change anything. Maybe the patches need to be updated? I would be happy to test again then.
Created attachment 317310 [details] [review] patch: Make it easier to use libsigc++ with Objective-C++ Here is an updated patch. Why would nil be a problem for you? Is nil a preprocessor macro in Mac OS C++? Or does Ardour use Objective-C++?
I'm inclined to push the patch in comment 8, but first I'd like to know if it fixes the problem with building Ardour on Mac OS X. It's surprising if nil is a problem now. Contrary to check() (bug 759315), nil is not new in libsigc++. struct nil has existed at least since the year 2003, libsigc++ 2.0.0. David, if you test it, note that it adds a new test in the configure file. Run autogen.sh to regenerate configure. Or add #define SIGC_PRAGMA_PUSH_POP_MACRO 1 manually in sigc++config.h after you run configure.
To answer your previous questions: No, as far as I know it dosen't use ObjC. But it uses some Mac frameworks, which use nil as an reserved keyword. MacTypes.h defines nil as nullptr (for C++11), is the reason that the definiton of "struct nil" by libsigc++ fails: /usr/local/Cellar/libsigc++/2.6.2/include/sigc++-2.0/sigc++/functors/functor_trait.h:18:1: error: declaration of anonymous struct must be a definition struct nil; /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/MacTypes.h:92:19: note: expanded from macro 'nil' #define nil nullptr MacTypes.h together with an vanilla libsigc++ may have never been used successfully (Ardour is using a patched libsigc++). Now with your patch applied and regenerating via autogen.sh, that works like a charm! Thank you!
I have pushed the patch, but with a new title: Temporarily undefine the nil macro, if it's defined https://git.gnome.org/browse/libsigc++2/commit/?id=75466ce1e1d92fe04926f72567417912779cc5c1
I have removed nil from libsigc++-3.0. We don't need it now that we have variadic templates. That code is currently in the variadic_bind4 branch but will eventually be in git master.