Opened 12 years ago

Closed 9 years ago

Last modified 8 years ago

#5010 closed Bugs (fixed)

Fusion will now compile under Objective-C++

Reported by: Brian Doig <Brian.Doig@…> Owned by: Joel de Guzman
Milestone: To Be Determined Component: fusion
Version: Boost 1.45.0 Severity: Showstopper
Keywords: Cc:

Description

I was attempting to use the boost::accumulators which relies on boost::fusion on the iPhone/Mac OS in a file that needs to know about Apple Objective-C data types using Objective-C++.

Line 21 of boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp declares the following:

struct nil;

This is illegal under Objective-C, and thus Objective C++ since nil is a reserved word. As a result, merely including any file that depends on cons_iterator.hpp results in error messages such as the following.

The easy fix for this is to change the name of the nil struct to anything other than a reserved word under Obj-C++.

/Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:21: error: expected identifier before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:21: error: expected unqualified-id before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:28: error: expected type-specifier before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:28: error: expected '>' before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:52: error: expected unqualified-id before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:54: error: type/value mismatch at argument 1 in template parameter list for 'template<class T> struct boost::add_const' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:54: error: expected a type, got '0' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:54: error: template argument 1 is invalid /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:57: error: expected unqualified-id before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:57: error: expected `)' before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:61: error: type/value mismatch at argument 1 in template parameter list for 'template<class Cons> struct boost::fusion::cons_iterator' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:61: error: expected a type, got '0' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:68: error: type/value mismatch at argument 1 in template parameter list for 'template<class Cons> struct boost::fusion::cons_iterator' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:68: error: expected a type, got '0' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:78: error: expected unqualified-id before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:78: error: expected `)' before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:85: error: expected unqualified-id before 'null' /Users/bdoig/Dropbox/Projects/boost_1_45_0/boost/fusion/container/list/cons_iterator.hpp:85: error: expected `)' before 'null'

Attachments (2)

fusion_nil_.diff (31.6 KB ) - added by Jürgen Hunold 11 years ago.
Patch replacing nil with nil_
fusion_nil_typename.patch (2.0 KB ) - added by Richard Eakin <reakinator@…> 9 years ago.
rename Nil to Nil_ for segmented_begin.hpp / segmented_end.hpp

Download all attachments as: .zip

Change History (43)

comment:1 by Joel de Guzman, 12 years ago

Resolution: wontfix
Status: newclosed

Oops. Sorry, wrong ticket. Please disregard this.

Last edited 12 years ago by Joel de Guzman (previous) (diff)

comment:2 by Joel de Guzman, 12 years ago

Resolution: wontfix
Status: closedreopened

comment:3 by Brian Doig <Brian.Doig@…>, 12 years ago

Glad it was the wrong ticket. It prevented using boost::accumulators and anything else that relied on Fusion impossible to use with Objective-C++ on the Mac/iOS

comment:4 by ufosky@…, 11 years ago

This bug is still exist in current release(1.47.0),I use boost::msm with Objective-C++,but it cause many errors

by Jürgen Hunold, 11 years ago

Attachment: fusion_nil_.diff added

Patch replacing nil with nil_

comment:5 by Jürgen Hunold, 11 years ago

This also clashes with LEDA-4.2 which uses a "nil" (for NULL) in the global namespace. I've attached a patch which replaces "nil" with "nil_" for fusion and all usage cases I've found. Run Boost unit tests with gcc-4.2 and clang-3.1 (trunk). Documentation is not patched.

Okay to commit?

comment:6 by anonymous, 11 years ago

I've also run into the same problem with 1.48.0 on Mac OS X using the 10.6 SDK. The header MacTypes.h #defines nil to NULL which causes the same "error: expected unqualified-id before 'null' " compilation error.

comment:7 by rowanj@…, 11 years ago

With current Xcode (4.2)

Building as Objective-C++ will include <objc/objc.h>, which contains:

#ifndef Nil
#define Nil __DARWIN_NULL	/* id of Nil class */
#endif

#ifndef nil
#define nil __DARWIN_NULL	/* id of Nil instance */
#endif

So this error will re-occur for nil or Nil (the current incarnation of this error for us in 1.48.0)

comment:8 by arne.schmitz@…, 11 years ago

Having the same problem with iOS SDK 5.0 on OS X 10.7.3 running Xcode 4.2. This minimal test program fails:

#import <CoreFoundation/CoreFoundation.h>
#include <boost/phoenix/core/reference.hpp>

int main()
{
    return 1;
}

Swapping the two header lines will result in successful compilation. Will now try the patch by jhunold, and see if it fixes my problem.

comment:9 by Joel de Guzman, 11 years ago

Allow me to reiterate that the proper patch for this is not a global rename of nil into something else. nil is part of the interface of fusion (and phoenix). It will break backward compatibility of we simply rename nil to, say, nil_. The acceptable patch is to do a rename *ONLY* for the affected libraries (e.g. LEDA) and platforms with a proper warning that nil is being renamed and will therefore break compatibility where/if it's used on such platforms or with such libraries.

comment:10 by matthew.davies@…, 10 years ago

I had the same problem - I just wrapped the #include statements with #undef nil and #define nil NULL. That seems to fix it since I don't use nil when calling the API.

comment:11 by justacec@…, 10 years ago

I have recently encountered this problem with Snow Leopard, Xcode 4.4.1, and Boots 1.50.0. I am not sure what the final answer will be to this but right now I have done the following:

#define nil Boost_nil
#define Nil Boost_Nil
<All of my boost header files>
#undef Nil
#undef nil

It might possibly be better to do the following instead based on the earlier response:

#define nil Boost_nil
#define Nil Boost_Nil
<All of my boost header files>
#define Nil __DARWIN_NULL
#define nil __DARWIN_NULL

The main problem here is that I am getting warnings, which I do not like to see, in my Xcode compiles.

Ohh, the drama...

Is there any progress on getting this fixed up?

comment:12 by CactusJack, 10 years ago

#ifdef nil
	#pragma push_macro("nil")
	#undef nil
	#include <boost/nil-struct-idiot.hpp>
	#pragma pop_macro("nil")
#else
	#include <boost/nil-struct-idiot.hpp>
#endif

might be more elegant and safer

comment:13 by anonymous, 10 years ago

the status should be changed 2 must be changed right now

struct struct{} class class {} idiot idiot{}

comment:14 by anonymous, 10 years ago

Joel for God sake swap your arse and change it, you did wrong, just admit it, it will save a lot of time and frustration to anyone

comment:15 by brian.doig@…, 10 years ago

"with a proper warning that nil is being renamed and will therefore break compatibility where/if it's used on such platforms or with such libraries."


The keyword nil is just a NULL pointer that is tagged with a different name so that the compiler knows to treat it as an objective-c object. Changing the definition of nil is equivalent to changing the definition of NULL under C++ to be something other than what the standard expects. That seems rather dangerous to me.

Under Obj-C++ you can legally message a nil pointer. It ignores the message and any return value is zero. There are many places in the language that depend on this functionality. Changing the definition of nil could potentially break code everywhere in an application

If you need to maintain nil for backwards compatibility purposes, then use a pre-processor test to check if the code is being compiled for objective-c and if so use a different symbol name. Or perhaps you could change it so that it's always nil_ but when not under objective-c you also define an alias of nil = nil_ so that the old code works.

Is this problem tough to fix? Yes, but the iPhone/iPad/Mac are going to become more popular and the missing libraries from boost due to this are going to become larger and larger problems as time goes by.

Nil is defined as follows. Perhaps there is some way to make the nil used by obj-c be semantically equivalent to how fusion defines nil?

<objc/objc.h>
#ifndef nil
#define nil __DARWIN_NULL /* id of Nil instance */
#endif

<sys/_types.h>
#ifdef __cplusplus
#ifdef __GNUG__
#define __DARWIN_NULL __null
#else /* ! __GNUG__ */
#ifdef __LP64__
#define __DARWIN_NULL (0L)
#else /* !__LP64__ */
#define __DARWIN_NULL 0
#endif /* __LP64__ */
#endif /* __GNUG__ */
#else /* ! __cplusplus */
#define __DARWIN_NULL ((void *)0)
#endif /* __cplusplus */

comment:16 by anonymous, 10 years ago

Please fix this! It makes using boost/fusion (or any boost lib that uses it, e.g. random) almost not worth it. The maintainers will have to face the fact that using the name "nil" was an extremely unfortunate decision in the first place. Unfortunately we are having to pay the price for it.

comment:17 by Joel de Guzman, 10 years ago

A patch has been added to boost trunk. Please test.

comment:18 by Mital Vora <mital.d.vora@…>, 10 years ago

Hi djowel,

I tried checking out boost svn version 82308 (latest atm) and tried to compile my code which was having same issue:

Here are the details

I am trying to use Boost Process module (http: www.highscore.de /boost/process0.5/index.html) in my code. I have downloaded the above library link provided in the above page (http: www.highscore.de /boost/process0.5/process.zip).

I have added the above files in include directories and trying to compile the same with my code:

All changes I have so far is just include following in any file:

` #include <boost/process.hpp> `

If I try to compile this with boost 1.52 released version, I get following error: http: pastebin.com /DLsF8LhT


My compiler is: i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00) Copyright (C) 2007 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Now when I try to compile the latest boost and try to use the same I am getting following error:

http: pastebin.com/GurfZsby

It seems that there are still places which requires ifdefing out the nil to nil_, e.g. file: boost/fusion/sequence/intrinsic/detail/segmented_end.hpp:21

I am ready to help you fix this. I will also try to check the code but I am not much familiar with the code so may require your assistance. Let me know what time you would be available for chat / irc.

Thanks, Mital

P.S. Adding spaces in the links because the trac seems to think they are spam links.

in reply to:  18 comment:19 by Joel de Guzman, 10 years ago

I am ready to help you fix this. I will also try to check the code but I am not much familiar with the code so may require your assistance. Let me know what time you would be available for chat / irc.

Thanks, Mital. I'm not sure when I'll be available for chat. I suggest just posting a patch here. Just follow the style of the recent patches. I can do the rest.

by Richard Eakin <reakinator@…>, 9 years ago

Attachment: fusion_nil_typename.patch added

rename Nil to Nil_ for segmented_begin.hpp / segmented_end.hpp

comment:20 by Richard Eakin <reakinator@…>, 9 years ago

The patch I just uploaded fixes the problem @Mital mentioned and also one I just ran into when trying to build boost log. Apparently 'Nil' also needs to be renamed to 'Nil_' to make Obj-C land happy.

comment:21 by Michael Caisse, 9 years ago

Committed change for template parameter name as Nil_ . Changeset [84441]

Last edited 9 years ago by viboes (previous) (diff)

comment:22 by Mital, 9 years ago

I have checked out the latest code .. but I am not able to compile the trunk at revision 84441

... falied darwin.compile.c++ bin.v2/lib/log/build/darwin-4.2.1/release/build-no/link-static/log-api-unix/threading-multi/filter_parser.o

It may not be related to the fixes u commited but I am not sure how can I verify the changes commited.

comment:23 by Richard Eakin <reakinator@…>, 9 years ago

How are you attempting to build? I agree it is currently difficult and I hope the author of Log addresses these concerns, but nontheless this is how I build on my machine (with clang / libc++):

add to tools/build/v2/user-config.jam:

using clang : osx
: xcrun clang -arch i386 -arch x86_64 -stdlib=libc++ -std=c++11
;

then:

./boostrap.sh --with-libraries=log
./b2 -a -d+2 -q toolset=clang-osx link=static address-model=64 stage 

comment:24 by Richard Eakin <reakinator@…>, 9 years ago

Or, you can skip building Log. :) The above will build Fusion, by the way, since it is a requirement.

in reply to:  22 ; comment:25 by Michael Caisse, 9 years ago

Replying to Mital:

I have checked out the latest code .. but I am not able to compile the trunk at revision 84441

... falied darwin.compile.c++ bin.v2/lib/log/build/darwin-4.2.1/release/build-no/link-static/log-api-unix/threading-multi/filter_parser.o

It may not be related to the fixes u commited but I am not sure how can I verify the changes commited.

Hi Mital -

This ticket refers to fusion... you are having build issues with something in log it would seem. If you would like to verify the fusion changes you can build the Fusion test or something that uses Fusion (which is a header-only library). The problem reported (and in theory fixed) relates to ObjC's bad behaviour of making things like nil and Nil special (via keyword or macro... I do not know).

Changing template parameters name Nil to Nil_ would not have broken log (o;

comment:26 by Mital, 9 years ago

I am building the entire boost with ./b2 install

I will try to build only fusion and test it.

Thanks Mital

in reply to:  25 comment:27 by Brian.Doig@…, 9 years ago

Replying to mjcaisse:

Replying to Mital:

I have checked out the latest code .. but I am not able to compile the trunk at revision 84441

... falied darwin.compile.c++ bin.v2/lib/log/build/darwin-4.2.1/release/build-no/link-static/log-api-unix/threading-multi/filter_parser.o

It may not be related to the fixes u commited but I am not sure how can I verify the changes commited.

Hi Mital -

This ticket refers to fusion... you are having build issues with something in log it would seem. If you would like to verify the fusion changes you can build the Fusion test or something that uses Fusion (which is a header-only library). The problem reported (and in theory fixed) relates to ObjC's bad behaviour of making things like nil and Nil special (via keyword or macro... I do not know).

Changing template parameters name Nil to Nil_ would not have broken log (o;

ObjC's so called bad behavior is part of the language specification since 1981 when it first originated, it is a strict superset of C. Because it's a strict superset of C it unfortunately does not have namespaces. By extension nil and Nil are is also part of the ObjC++ language specification, and have been for years. Fusion seems to have been introduced in version 1.35.0 on March 29th 2008. The problem is that there is a name space conflict with some language keywords.

In 2008, there was really no reason to consider ObjC++ and was thus the library was not written with ObjC++ in mind. This was a perfectly reasonable thing at the time. The rapid rise of OS X and iOS have increased the need to use boost on those platforms. Since Fusion is used in many places in boost, the fact that it won't compile due to a language keyword conflict is an issue that prevents large parts of boost being used easily on those operating systems.

The best work around I have found is to use pure C code to interface into the code using maps of integers to objects for handles. It's such a pain, I just don't use those modules of Boost that require fusion, even though many of them are perfect for what I need to do. I just end up reinventing those parts of boost poorly.

When I originally ran into the problem, I was using the header only libraries. All I had to do to duplicate the issue was to create an objective-c command line project in Xcode. Then I changed the main file extension to mm which instructs Xcode to use the Objective C++ compiler. I then included headers for fusion at the top of the file without changing the code. The build would fail to build because it couldn't parse the header files.

comment:28 by viboes, 9 years ago

It seems that the issue is solved, isn't it?

comment:29 by Joel de Guzman, 9 years ago

Resolution: fixed
Status: reopenedclosed

comment:30 by brian.doig@…, 9 years ago

What version is this fixed in? I just downloaded 1.54 and it's still failing to compile.

#include <boost/accumulators/accumulators.hpp>

still results in:

In file included from /Users/Doig/Documents/Projects/BoostTest/BoostTest/BTAppDelegate.mm:9: In file included from /Users/Doig/Documents/Projects/boost_1_54_0/boost/accumulators/accumulators.hpp:12: In file included from /Users/Doig/Documents/Projects/boost_1_54_0/boost/accumulators/framework/accumulator_set.hpp:23: In file included from /Users/Doig/Documents/Projects/boost_1_54_0/boost/accumulators/framework/depends_on.hpp:40: In file included from /Users/Doig/Documents/Projects/boost_1_54_0/boost/fusion/include/equal_to.hpp:11: In file included from /Users/Doig/Documents/Projects/boost_1_54_0/boost/fusion/sequence/comparison/equal_to.hpp:11: In file included from /Users/Doig/Documents/Projects/boost_1_54_0/boost/fusion/sequence/intrinsic/begin.hpp:17: In file included from /Users/Doig/Documents/Projects/boost_1_54_0/boost/fusion/sequence/intrinsic/detail/segmented_begin.hpp:10: In file included from /Users/Doig/Documents/Projects/boost_1_54_0/boost/fusion/sequence/intrinsic/detail/segmented_begin_impl.hpp:11: /Users/Doig/Documents/Projects/boost_1_54_0/boost/fusion/container/list/cons_fwd.hpp:13:5: error: declaration of anonymous struct must be a definition

struct nil;

/Users/Doig/Documents/Projects/boost_1_54_0/boost/fusion/container/list/cons_fwd.hpp:13:5: warning: declaration does not declare anything [-Wmissing-declarations]

struct nil; ~

/Users/Doig/Documents/Projects/boost_1_54_0/boost/fusion/container/list/cons_fwd.hpp:15:44: error: expected a type

template <typename Car, typename Cdr = nil>

comment:31 by catskin@…, 9 years ago

Certainly not fixed. I was trying out the log library on 1.54.0, (including <boost/log/expressions.hpp>) and it led to this compiler error:

namespace boost { namespace fusion {

struct nil; <-------------------------

template <typename Car, typename Cdr = nil> struct cons;

}}

among others.

comment:32 by anonymous, 9 years ago

patience. it will be merged in the next boost release.

comment:33 by anonymous, 9 years ago

I downloaded and checked boost 1.55beta... the fix is not in there.

comment:34 by brianmar, 9 years ago

Definitely not fixed int eh 1.55 Boost that installs with MacPorts. Still getting an error when I try to compile boost/spirit/include/qi.hpp. Error at line 45 of make_cons.hpp, due to the "nil".

comment:35 by Joel de Guzman, 9 years ago

Resolution: fixed
Status: closedreopened

Alright. I reopened this. I'll verify this as soon as I can. I'll need someone to do the testing as I have no way to test it myself. brianmar, send me an email (djowel at gmail dot com) and let's fix this once and for all.

Last edited 9 years ago by Joel de Guzman (previous) (diff)

comment:37 by anonymous, 9 years ago

I've tested the changes by pulling down all of https://github.com/boostorg/boost and running the command lines to create the header files. After that the code compiled fusion, msm and accumulators when I included their header files. The sample code I pulled from the examples all seemed to work as well.

comment:38 by Joel de Guzman, 9 years ago

Great. It's just a matter of merging to 'master' then. It might have been a bad merge. Better yet, if you could send a test cpp file that simulates this by defining some nasty symbols like nil, etc., then it can be part of the regression test.

comment:39 by Joel de Guzman, 9 years ago

Resolution: fixed
Status: reopenedclosed

in reply to:  34 comment:40 by anonymous, 8 years ago

Replying to brianmar:

Definitely not fixed int eh 1.55 Boost that installs with MacPorts. Still getting an error when I try to compile boost/spirit/include/qi.hpp. Error at line 45 of make_cons.hpp, due to the "nil".

I've noticed this too. It's not a fusion problem but a spirit problem. You need to replace the "nil" with "nil_" in boost/spirit/home/support/detail/make_cons.hpp, boost/spirit/home/support/context.hpp, boost/spirit/home/support/make_component.hpp and boost/spirit/home/support/info.hpp. The first three refer to fusion::nil (which needs to be changed to match fusion) and the latter is spirit's own definition which should be changed for similar reasons.

comment:41 by Joel de Guzman, 8 years ago

Please prepare a pull request here: https://github.com/boostorg/spirit

Note: See TracTickets for help on using tickets.