Skip to content
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

Merged
merged 1 commit into from
Feb 27, 2017

Conversation

mjerris
Copy link
Contributor

@mjerris mjerris commented Feb 22, 2017

These macros allow us to activate compiler visibility flags (gcc) and dllimport/dllexport (windows).

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 22, 2017

Can you please explain what this does and why it is necessary!

I was assuming that the use of static and extern for specifying the storage class was sufficient.

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.

@mjerris
Copy link
Contributor Author

mjerris commented Feb 23, 2017

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.

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 23, 2017

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?

@mjerris
Copy link
Contributor Author

mjerris commented Feb 23, 2017

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;

Copy link
Collaborator

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explains what exactly?

Copy link
Collaborator

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.

Copy link
Contributor Author

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
Copy link
Collaborator

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)

Copy link
Contributor Author

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
Copy link
Collaborator

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
Copy link
Collaborator

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.

Copy link
Collaborator

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

Copy link
Contributor Author

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?

Copy link
Collaborator

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)
Copy link
Collaborator

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.

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 26, 2017

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:

  • Please redo the Pull request to the develop branch
  • Please add the same to cJSON_Utils
  • Please make the changes requested in my comments.

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 CJSON_EXPORT_SYMBOLS. You can also use CMake in order to find out if it was statically or dynamically compiled.

@mjerris
Copy link
Contributor Author

mjerris commented Feb 27, 2017

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).

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

Don't worry about pure make. In this case you can just rely on the user passing in the defines manually.

Just CMake.

@mjerris mjerris changed the base branch from master to develop February 27, 2017 19:06
@mjerris
Copy link
Contributor Author

mjerris commented Feb 27, 2017

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
Copy link
Collaborator

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushed that change

@mjerris
Copy link
Contributor Author

mjerris commented Feb 27, 2017

can you clarify what the different branches are and where this patch is targeted to?

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

I haven't really formalised it.

  • v1 was originally intended for fixes once version 2 is out. But currently it doesn't really serve any purpose.
  • v2 is just the branch where I do breaking changes for version 2, it has been and will be rebased frequently, don't base anything off that
  • develop was just added recently and I plan to use this branch for all the development work that will go into the next release.
  • master is now intended to always be the same as the latest release, or contain small bugfixes that will increase the third number of the version number.

I plan to release version 1.4.0 including your changes and what I did on the develop branch.

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

I should add a CONTRIBUTING.md, but I haven't come around to write one.

@mjerris
Copy link
Contributor Author

mjerris commented Feb 27, 2017

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?

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

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.

@mjerris
Copy link
Contributor Author

mjerris commented Feb 27, 2017

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.

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

Looks good to me. I will merge this now.

@FSMaxB FSMaxB merged commit 024f690 into DaveGamble:develop Feb 27, 2017
@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

Thank you very much for your contribution to cJSON.

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

One additional question: Would it be a sensible default to always set CJSON_EXPORT_SYMBOLS on windows?

@mjerris
Copy link
Contributor Author

mjerris commented Feb 27, 2017

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

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

Not the makefile, but CMake.

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

Maybe the makefile as well.

@mjerris
Copy link
Contributor Author

mjerris commented Feb 27, 2017

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)

@mjerris
Copy link
Contributor Author

mjerris commented Feb 27, 2017

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

@FSMaxB
Copy link
Collaborator

FSMaxB commented Feb 27, 2017

Ok, thanks. I think I will set defaults when building as shared lib, otherwise don't do anything if no CMake option was set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants