Skip to content
This repository has been archived by the owner on Mar 26, 2020. It is now read-only.

Add support for -fvisibility=hidden and -fvisibility=default flags #415

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ include(GNUInstallDirs)

set(SRC_SHARED
"support-lib/djinni_common.hpp"
"support-lib/project_export.hpp"
Copy link
Contributor

Choose a reason for hiding this comment

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

This is used so widely (requiring it to be in the include path) that it really needs a more unique name, like djinni_project_export.hpp.

"support-lib/proxy_cache_interface.hpp"
"support-lib/proxy_cache_impl.hpp"
)
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,23 @@ In order to do that, there are two steps needed:
- deriving the records that should be parcelable with the keyword parcelable: `deriving(parcelable)`
- run Djinni with the following flag `--java-implement-android-os-parcelable true`

## Support for `-fvisibility=hidden` and `-fvisibility=default`

You can pass `-fvisibility=hidden` or the `-fvisibility=default` flags to your compiler, Djinni handles both cases well.

The symbols that are belonging to the public interfaces that are generated by Djinni are automatically defined to be visible symbols.
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like it's not obvious that making these symbols always public is the right behavior for all users. E.g. if Djinni symbols are only used internally to a larger library, they wouldn't need to be exported. In the use case we've used at Dropbox, we build all our C++ code into a single library on Android, so only the JNI functions need to be exported.

To achieve this Djinni is marking the generated code with `PROJECT_EXPORT`.
`PROJECT_EXPORT` is defined in `support-lib/project_export.hpp`.
This macro is using the correct attribute specifier for the actual compiler. For more details, please check the macro definition in the `support-lib/project_export.hpp` header.

Since the generated headers are including this `support-lib/project_export.hpp` header, you must distribute this header together with your library that is using Djinni.

### Windows

For Windows builds, you must define `BUILDING_DLL` based on your needs.
You can define it as a compiler option like `-DBUILDING_DLL`.
For more details, please check the macro definition in the `support-lib/project_export.hpp` header.

## Community Links

* Join the discussion with other developers at the [Mobile C++ Slack Community](https://mobilecpp.herokuapp.com/)
Expand Down
26 changes: 15 additions & 11 deletions src/source/CppGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
val refs = new CppRefs(ident.name)
val self = marshal.typename(ident, e)

refs.hpp.add("#include \"project_export.hpp\"")
if (spec.cppEnumHashWorkaround) {
refs.hpp.add("#include <functional>") // needed for std::hash
}
Expand Down Expand Up @@ -101,7 +102,7 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
wrapNamespace(w, "std",
(w: IndentWriter) => {
w.wl("template <>")
w.w(s"struct hash<$fqSelf>").bracedSemi {
w.w(s"struct PROJECT_EXPORT hash<$fqSelf>").bracedSemi {
w.w(s"size_t operator()($fqSelf type) const").braced {
w.wl(s"return std::hash<$underlyingType>()(static_cast<$underlyingType>(type));")
}
Expand Down Expand Up @@ -177,7 +178,7 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
if (shouldConstexpr(c)){
w.w(s"${marshal.fieldType(c.ty)} constexpr $selfName::${idCpp.const(c.ident)}")
} else {
w.w(s"${marshal.fieldType(c.ty)} const $selfName::${idCpp.const(c.ident)} = ")
w.w(s"PROJECT_EXPORT ${marshal.fieldType(c.ty)} const $selfName::${idCpp.const(c.ident)} = ")
writeCppConst(w, c.ty, c.value)
}
w.wl(";")
Expand All @@ -188,6 +189,7 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
val refs = new CppRefs(ident.name)
r.fields.foreach(f => refs.find(f.ty, false))
r.consts.foreach(c => refs.find(c.ty, false))
refs.hpp.add("#include \"project_export.hpp\"")
refs.hpp.add("#include <utility>") // Add for std::move

val self = marshal.typename(ident, r)
Expand All @@ -202,13 +204,13 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
// C++ Header
def writeCppPrototype(w: IndentWriter) {
if (r.ext.cpp) {
w.w(s"struct $self; // Requiring extended class")
w.w(s"struct PROJECT_EXPORT $self; // Requiring extended class")
w.wl
w.wl
}
writeDoc(w, doc)
writeCppTypeParams(w, params)
w.w("struct " + actualSelf + cppFinal).bracedSemi {
w.w("struct PROJECT_EXPORT " + actualSelf + cppFinal).bracedSemi {
generateHppConstants(w, r.consts)
// Field definitions.
for (f <- r.fields) {
Expand All @@ -218,18 +220,18 @@ class CppGenerator(spec: Spec) extends Generator(spec) {

if (r.derivingTypes.contains(DerivingType.Eq)) {
w.wl
w.wl(s"friend bool operator==(const $actualSelf& lhs, const $actualSelf& rhs);")
w.wl(s"friend bool operator!=(const $actualSelf& lhs, const $actualSelf& rhs);")
w.wl(s"PROJECT_EXPORT friend bool operator==(const $actualSelf& lhs, const $actualSelf& rhs);")
w.wl(s"PROJECT_EXPORT friend bool operator!=(const $actualSelf& lhs, const $actualSelf& rhs);")
}
if (r.derivingTypes.contains(DerivingType.Ord)) {
w.wl
w.wl(s"friend bool operator<(const $actualSelf& lhs, const $actualSelf& rhs);")
w.wl(s"friend bool operator>(const $actualSelf& lhs, const $actualSelf& rhs);")
w.wl(s"PROJECT_EXPORT friend bool operator<(const $actualSelf& lhs, const $actualSelf& rhs);")
w.wl(s"PROJECT_EXPORT friend bool operator>(const $actualSelf& lhs, const $actualSelf& rhs);")
}
if (r.derivingTypes.contains(DerivingType.Eq) && r.derivingTypes.contains(DerivingType.Ord)) {
w.wl
w.wl(s"friend bool operator<=(const $actualSelf& lhs, const $actualSelf& rhs);")
w.wl(s"friend bool operator>=(const $actualSelf& lhs, const $actualSelf& rhs);")
w.wl(s"PROJECT_EXPORT friend bool operator<=(const $actualSelf& lhs, const $actualSelf& rhs);")
w.wl(s"PROJECT_EXPORT friend bool operator>=(const $actualSelf& lhs, const $actualSelf& rhs);")
}

// Constructor.
Expand Down Expand Up @@ -322,13 +324,15 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
refs.find(c.ty, true)
})

refs.hpp.add("#include \"project_export.hpp\"")

val self = marshal.typename(ident, i)
val methodNamesInScope = i.methods.map(m => idCpp.method(m.ident))

writeHppFile(ident, origin, refs.hpp, refs.hppFwds, w => {
writeDoc(w, doc)
writeCppTypeParams(w, typeParams)
w.w(s"class $self").bracedSemi {
w.w(s"class PROJECT_EXPORT $self").bracedSemi {
w.wlOutdent("public:")
// Destructor
w.wl(s"virtual ~$self() {}")
Expand Down
4 changes: 4 additions & 0 deletions src/source/ObjcGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,14 @@ class ObjcGenerator(spec: Spec) extends BaseObjcGenerator(spec) {
writeObjcFile(marshal.headerName(ident), origin, refs.header, w => {
for (c <- i.consts if marshal.canBeConstVariable(c)) {
writeDoc(w, c.doc)
w.wl("__attribute__((visibility (\"default\")))")
w.w(s"extern ")
writeObjcConstVariableDecl(w, c, self)
w.wl(s";")
}
w.wl
writeDoc(w, doc)
w.wl("__attribute__((visibility (\"default\")))")
if (i.ext.objc) w.wl(s"@protocol $self") else w.wl(s"@interface $self : NSObject")
for (m <- i.methods) {
w.wl
Expand Down Expand Up @@ -164,6 +166,7 @@ class ObjcGenerator(spec: Spec) extends BaseObjcGenerator(spec) {
// Generate the header file for record
writeObjcFile(marshal.headerName(objcName), origin, refs.header, w => {
writeDoc(w, doc)
w.wl("__attribute__((visibility (\"default\")))")
w.wl(s"@interface $self : NSObject")

def writeInitializer(sign: String, prefix: String) {
Expand Down Expand Up @@ -198,6 +201,7 @@ class ObjcGenerator(spec: Spec) extends BaseObjcGenerator(spec) {
w.wl
for (c <- r.consts if marshal.canBeConstVariable(c)) {
writeDoc(w, c.doc)
w.wl("__attribute__((visibility (\"default\")))")
w.w(s"extern ")
writeObjcConstVariableDecl(w, c, noBaseSelf);
w.wl(s";")
Expand Down
1 change: 1 addition & 0 deletions src/source/ObjcppGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class ObjcppGenerator(spec: Spec) extends BaseObjcGenerator(spec) {

if (i.ext.cpp) {
w.wl
w.wl("__attribute__((visibility (\"default\")))")
if (i.ext.objc)
w.wl(s"@interface $objcSelf : NSObject<$self>")
else
Expand Down
1 change: 1 addition & 0 deletions src/source/generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ abstract class Generator(spec: Spec)
w.wl("// This file generated by Djinni from " + origin)
w.wl
val myHeader = q(includePrefix + fileIdentStyle(name) + "." + spec.cppHeaderExt)
w.wl("#include \"project_export.hpp\"")
w.wl(s"#include $myHeader // my header")
val myHeaderInclude = s"#include $myHeader"
for (include <- includes if include != myHeaderInclude)
Expand Down
42 changes: 42 additions & 0 deletions support-lib/project_export.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Copyright 2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef PROJECT_EXPORT
# if defined _WIN32 || defined __CYGWIN__
# ifdef BUILDING_DLL
# ifdef __GNUC__
# define PROJECT_EXPORT __attribute__((dllexport))
# else
# define PROJECT_EXPORT __declspec(dllexport)
# endif
# else
# ifdef __GNUC__
# define PROJECT_EXPORT __attribute__((dllimport))
# else
# define PROJECT_EXPORT __declspec(dllimport)
# endif
# endif
# define PROJECT_LOCAL
# else
# if __GNUC__ >= 4
# define PROJECT_EXPORT __attribute__((visibility("default")))
# define PROJECT_LOCAL__attribute__ ((visibility("hidden")))
# else
# define PROJECT_EXPORT
# define PROJECT_LOCAL
# endif
# endif
#endif
1 change: 1 addition & 0 deletions support-lib/support_lib.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"type": "static_library",
"sources": [
"djinni_common.hpp",
"project_export.hpp",
"jni/djinni_support.cpp",
"jni/djinni_support.hpp",
"jni/Marshal.hpp",
Expand Down
4 changes: 3 additions & 1 deletion test-suite/generated-src/cpp/Conflict.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@

#pragma once

#include "project_export.hpp"

namespace testsuite {

/**
* Test for conflict of method name with an interface name.
* See the comments about scopeSymbols in CppMarshal.scala for more info.
*/
class Conflict {
class PROJECT_EXPORT Conflict {
public:
virtual ~Conflict() {}
};
Expand Down
3 changes: 2 additions & 1 deletion test-suite/generated-src/cpp/_varname_interface_.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

#pragma once

#include "project_export.hpp"
#include <memory>

namespace testsuite {

struct VarnameRecord;

class VarnameInterface {
class PROJECT_EXPORT VarnameInterface {
public:
virtual ~VarnameInterface() {}

Expand Down
3 changes: 2 additions & 1 deletion test-suite/generated-src/cpp/_varname_record_.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "project_export.hpp"
#include <cstdint>
#include <utility>

Expand All @@ -13,7 +14,7 @@ namespace testsuite {
* anticipate it to be used as a prefix/suffix. Some name styles behave
* badly when it is. However this test case ensures we at least don't crash.
*/
struct VarnameRecord final {
struct PROJECT_EXPORT VarnameRecord final {
int8_t _field_;

VarnameRecord(int8_t _field__)
Expand Down
3 changes: 2 additions & 1 deletion test-suite/generated-src/cpp/access_flags.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "project_export.hpp"
#include <functional>

namespace testsuite {
Expand Down Expand Up @@ -47,7 +48,7 @@ constexpr access_flags operator~(access_flags x) noexcept {
namespace std {

template <>
struct hash<::testsuite::access_flags> {
struct PROJECT_EXPORT hash<::testsuite::access_flags> {
size_t operator()(::testsuite::access_flags type) const {
return std::hash<unsigned>()(static_cast<unsigned>(type));
}
Expand Down
1 change: 1 addition & 0 deletions test-suite/generated-src/cpp/assorted_primitives.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from primtypes.djinni

#include "project_export.hpp"
#include "assorted_primitives.hpp" // my header

namespace testsuite {
Expand Down
7 changes: 4 additions & 3 deletions test-suite/generated-src/cpp/assorted_primitives.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
#pragma once

#include "../../handwritten-src/cpp/optional.hpp"
#include "project_export.hpp"
#include <cstdint>
#include <utility>

namespace testsuite {

struct AssortedPrimitives final {
struct PROJECT_EXPORT AssortedPrimitives final {
bool b;
int8_t eight;
int16_t sixteen;
Expand All @@ -25,8 +26,8 @@ struct AssortedPrimitives final {
std::experimental::optional<float> o_fthirtytwo;
std::experimental::optional<double> o_fsixtyfour;

friend bool operator==(const AssortedPrimitives& lhs, const AssortedPrimitives& rhs);
friend bool operator!=(const AssortedPrimitives& lhs, const AssortedPrimitives& rhs);
PROJECT_EXPORT friend bool operator==(const AssortedPrimitives& lhs, const AssortedPrimitives& rhs);
PROJECT_EXPORT friend bool operator!=(const AssortedPrimitives& lhs, const AssortedPrimitives& rhs);

AssortedPrimitives(bool b_,
int8_t eight_,
Expand Down
3 changes: 2 additions & 1 deletion test-suite/generated-src/cpp/client_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include "../../handwritten-src/cpp/optional.hpp"
#include "project_export.hpp"
#include <cstdint>
#include <memory>
#include <string>
Expand All @@ -14,7 +15,7 @@ namespace testsuite {
struct ClientReturnedRecord;

/** Client interface */
class ClientInterface {
class PROJECT_EXPORT ClientInterface {
public:
virtual ~ClientInterface() {}

Expand Down
3 changes: 2 additions & 1 deletion test-suite/generated-src/cpp/client_returned_record.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
#pragma once

#include "../../handwritten-src/cpp/optional.hpp"
#include "project_export.hpp"
#include <cstdint>
#include <string>
#include <utility>

namespace testsuite {

/** Record returned by a client */
struct ClientReturnedRecord final {
struct PROJECT_EXPORT ClientReturnedRecord final {
int64_t record_id;
std::string content;
std::experimental::optional<std::string> misc;
Expand Down
3 changes: 2 additions & 1 deletion test-suite/generated-src/cpp/color.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "project_export.hpp"
#include <functional>

namespace testsuite {
Expand All @@ -27,7 +28,7 @@ enum class color : int {
namespace std {

template <>
struct hash<::testsuite::color> {
struct PROJECT_EXPORT hash<::testsuite::color> {
size_t operator()(::testsuite::color type) const {
return std::hash<int>()(static_cast<int>(type));
}
Expand Down
3 changes: 2 additions & 1 deletion test-suite/generated-src/cpp/conflict_user.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

#pragma once

#include "project_export.hpp"
#include <memory>
#include <unordered_set>

namespace testsuite {

class Conflict;

class ConflictUser {
class PROJECT_EXPORT ConflictUser {
public:
virtual ~ConflictUser() {}

Expand Down
Loading