-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add CJSON_DECLARE macros to support gcc visibility and windows dllexport #116
Conversation
Can you please explain what this does and why it is necessary! I was assuming that the use of In general I don't want to include any macros to cJSON that check for the environment or available features and what not, as long as it is not completely unavoidable. |
sure. There are two things in here. I guess of a bit of note, on functions, extern is actually implicitly there, and you don't need to specify it (data is a bit different in this regard), your totally correct about static. There are two places this doesn't address. The first is on windows, what symbols are exposed from a dll need to be specified, either with a manual list or preferably by specifying dllexport (and when you use it dllimport) ... you can see that in the macro. The second is a similar feature added in the last 10 years or so to gcc (and clang) called visibility. This allows you to specify which symbols will be exported from an so. An example of when you might want to use visibility would be when you have a large project and you want some symbols to only be used within the so (but in different files) and others that are publicly exported. The macros I added make it possible to address all of these situations just by passing different defines at build time. |
Isn't it enough to specify this in the header where the function prototypes are instead of doing it in both the header and C file? |
unfortunately no, then you'll get declaration differs from definition type errors. |
@@ -81,84 +81,113 @@ typedef struct cJSON_Hooks | |||
void (*free_fn)(void *ptr); | |||
} cJSON_Hooks; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment that explains this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
explains what exactly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What the export does. And why it is needed for DLLs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gotcha. The comment was above that block so in github UI you can't see what you are referring to. Sure, no problem with this.
cJSON.h
Outdated
#if defined(CJSON_DECLARE_STATIC) | ||
#define CJSON_DECLARE(type) type __stdcall | ||
#define CJSON_DECLARE_NONSTD(type) type __cdecl | ||
#define CJSON_DECLARE_DATA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove CJSON_DECLARE_NONSTD
and CJSON_DECLARE_DATA
. (also from other branches of the if)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah these are not used here.. leftovers from other places i've used similar approach. I'll remove.
cJSON.h
Outdated
#endif | ||
#else /* !WIN32 */ | ||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) | ||
#define CJSON_DECLARE(type) __attribute__((visibility("default"))) type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to declare the "default"
visibility? If not, please remove.
cJSON.h
Outdated
#endif | ||
#ifdef __WINDOWS__ | ||
#if defined(CJSON_DECLARE_STATIC) | ||
#define CJSON_DECLARE(type) type __stdcall |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the __stdcall
necessary? If not, please make CJSON_DECLARE
a macro that doesn't take any parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also rename CJSON_DECLARE
to CJSON_PUBLIC
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it used to be required. I'll test if it defaults sanely now. I think it defaults to cdecl, which may be fine in this case. I'll review to confirm. It would be much nicer to be able to do this without needing the arg in the macro. I know in the past this didn't work. Are you ok if it works on modern compilers but not older ones?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it is not possible to do this on old compilers otherwise, than keep it as it is.
cJSON.h
Outdated
#define CJSON_DECLARE(type) type __stdcall | ||
#define CJSON_DECLARE_NONSTD(type) type __cdecl | ||
#define CJSON_DECLARE_DATA | ||
#elif defined(CJSON_EXPORTS) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename CJSON_EXPORTS
to CJSON_EXPORT_SYMBOLS
.
Sorry for taking so long to respond. First of all thank you for putting you time and effort into cJSON. I will accept this change, but I would like some changes:
If possible, add support to the build system, but I can do it, if you are not comfortable with cmake. There should be an option for |
in regards to make changes... its a bit tricky to do this without something like autoconf i can pass args to. I could make a bunch more targets for different combinations, but in pure make this ends up being a bit messy and some things would require conditions that are gnu make specific. What exactly did you have in mind. for example, it makes sense to by default use visibility where you can in the case of building dynamic, but building static, you may or may not want to have symbols exported based on usage (an example use case would be where you are building static for linking into another dynamic lib, but you may or may not want the symbols exported out of that lib). |
Don't worry about pure make. In this case you can just rely on the user passing in the defines manually. Just CMake. |
I think this covers all the change requests. Let me know what else you see. |
cJSON.h
Outdated
|
||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: | ||
|
||
CJSON_DECLARE_STATIC - Define this in the case where you don't want to ever dllexport symbols |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if I understand correctly. But this is not related to building static or dynamic libraries, right?
In this case I think CJSON_HIDE_SYMBOLS
would be a better name and it could also set the visibility to hidden for the *nix compilers. Or did I misunderstand that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is not directly related to building static or dynamic, it has to do with which symbols will be exported from the dll. if you set that define, it would export no symbols, but lets say you built static then linked it into another dll, you could use the symbols inside the dll, but would not be able to use them on the outside of the dll. agree with the name change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pushed that change
…dllimport/dllexport
can you clarify what the different branches are and where this patch is targeted to? |
I haven't really formalised it.
I plan to release version 1.4.0 including your changes and what I did on the |
I should add a |
sounds good.. does it matter that the other commit in master (the buffer overrun one) is not in develop branch right now, or develop will merge back to master pre-release? |
No problem, git handles merges like that quite well. And if it doesn't it's my job to fix it. You should never try to prevent merge conflicts by duplicating a commit so that it exists in both branches. |
yep, get that, just didn't know how your workflow works. Okay. I think you have it all from me now. Let me know if you need anything else. |
Looks good to me. I will merge this now. |
Thank you very much for your contribution to cJSON. |
One additional question: Would it be a sensible default to always set |
from the Makefile, yes, from the header file no... you want it to hit the dllimport branch of that #if for people using the lib and the dllexport branch when building the lib itself |
Not the makefile, but CMake. |
Maybe the makefile as well. |
it makes sense in cmake to add flags. to choose which. For shared lib, defaulting to export on windows makes sense. For static lib, its arguable what the better default should be. On the *nix side, something similar makes sense. I do a check if visibility is available, and if so, set the cflags for hidden, then set the define to expose the symbols (again on shared lib that makes sense, on static, its arguable what the default would be) |
you can see what i do in freeswitch here (its autoconf but the basic idea should be clear enough) .. search for visibility in this file: https://freeswitch.org/stash/projects/FS/repos/freeswitch/browse/configure.ac |
Ok, thanks. I think I will set defaults when building as shared lib, otherwise don't do anything if no CMake option was set. |
These macros allow us to activate compiler visibility flags (gcc) and dllimport/dllexport (windows).