I'm new to Protocol Buffers(PB). Now i need to communicate with 2 third-party service using PB.
But it fails to work with this compiling error:
cxs_service.pb.h: ISO C++ forbids declaration of TSResponse' with no type
cxs_service.pb.h: error: invalid use of::'
My header files include 2 3rd-party .h files looking like this:
#include "mob/include/ts_service.pb.h"
#include "pc/include/cxs_service.pb.h"
//### pc/include/cxs_service.pb.h ###
// The compiler seems to find ts_service.pb.h under pc/include successfully
// but it cannot recognize ::pc::TSResponse which is defined in it
# include "ts_service.pb.h"
namespace pc {
class CXSRequest : public ::google::protobuf::Message {
inline const ::pc::TSResponse& ts_response() const;
} // class CXSRequest
} // namespace pc
// i've found that mob/include/ts_service.pb.h, pc/include/ts_service.pb.h have the same header guard.
// Thus pc/include/cxs_service.pb.h really found pc/include/ts_service.pb.h.
// but cannot include it's content because of exactly the same header guard.
#ifndef PROTOBUF_ts_5fservice_2eproto__INCLUDED
#define PROTOBUF_ts_5fservice_2eproto__INCLUDED
#endif
the first 3rd-party PB message:
// ts_service.proto
package mob;
message TSResponse {
required uint64 id = 1;
}
the second 3rd-party PB message:
// cxs_service.proto
package pc;
import ts_service.proto;
message CXSRequest {
optional TSResponse ts_response = 1;
}
// which depends on its own ts_service.proto:
// ts_service.proto
package pc;
message TSResponse {
optional string name = 1;
}
It sounds like the problem is that there are two different ts_service.proto files with conflicting definitions. Normally you would solve this by putting each package's protos in a different directory, e.g. pc/ts_service.proto and mob/ts_service.proto.
Note that when using protoc to compile these files, you will want to set up the import path to point at the parent of these two directories; do not add each directory to the path directly as this will lead to the same conflict. That is:
# BAD
protoc -Isrc/pc -Isrc/mob src/pc/cxs_service.proto
# GOOD
protoc -Isrc src/pc/cxs_service.proto
Note that the import statements in each .proto will have to be updated to give the full path of the file being imported, i.e. import "/pc/ts_service.proto"; instead of import "ts_service.proto";.
Related
I have a big school project with an ESP32. Almost all GPIOs are used in the project, so I want to have the whole thing a bit cleaner.
If I declare all GPIOs in the main then it doesn't look so nice. Therefore I created a header file where all GPIOs are declared.
Here is an example:
//setPinConfig.h
const int start = 13;
const int stop = 9;
void setPinConfig()
{
pinMode(start, INPUT);
pinMode(stop, INPUT);
}
Then I call this function in the setup of the Main function.
//main.cpp
#include "setPinConfig.h"
void setup()
{
setPinConfig();
}
In the main, everything works the way I want it to. But if I now want to access the GPIOs in other header files, it comes to errors.
I work around this by using "#ifndef", #define, #endif in the header files in which I call the GPIO header file.
I am now wondering if this is a legitimate way to deklare and load the GPIOs. Or should I rather declare and load it classically in the main.
In short, you can't define functions in the header files (technically you can, but then you're in a world of pain). You define them in the .c or .cpp file, and declare in the .h file.
If you wish to create a new module (pair of .h and .c files) for configuring GPIO pins, it would look something like so:
Sample setPinConfig.h file:
#ifndef _SET_PIN_CONFIG
#define _SET_PIN_CONFIG
const int start = 13;
const int stop = 9;
// This function sets the GPIO pins' configuration
void setPinConfig();
#endif // _SET_PIN_CONFIG
Then sample setPinConfig.c
#include "setPinConfig.h"
void setPinConfig()
{
pinMode(start, INPUT);
pinMode(stop, INPUT);
}
I created a shared library using BOOST using the following to specify the factory method:
BOOST_DLL_ALIAS_SECTIONED(
MyPlugin::create, // Plugin's factory method being exported
create_plugin, // Alias for factory method.
MySectionName) // The section name that all factory methods are grouped in.
The create() method returns a shared pointer to the MyPlugin object.
I then load the shared library and try to fetch the particular section using:
boost::dll::library_info inf(shared_library_path);
And then locate the above section with:
std::vector<std::string> sections = inf.sections();
if (std::find(sections.begin(), sections.end(), "MySectionName") == sections.end()) {
// Do something
} else
{
// Error out
}
If the shared library was not stripped, the above allows me to find
MySectionName within its contents and perform actions within the bracket.
If I however strip the shared library (default: strip library_name.so), the
above library info no longer lists the defined section and I hit the error out
condition.
I can protect the particular factory method during strip by specifying
"-Kcreate" flag, but while that works with this simple shared library, more
complex libraries end up with more missing symbols and it almost feels
counterproductive to keep expanding the "-K" flag.
Is here an easier way of using BOOST for plugin creation using the above method
and still allow stripping out debug information without having to expand with
"-K" flag?
Thank you
I couldn't reproduce this with shorter section names:
File test.cpp
#include <boost/dll.hpp>
#include <boost/dll/alias.hpp>
namespace MyPlugin {
struct X{};
static auto create() {
return std::make_shared<X>();
}
}
BOOST_DLL_ALIAS_SECTIONED(
MyPlugin::create,
Factory,
MySect)
File test1.cpp
#include <boost/dll.hpp>
#include <iostream>
int main() {
boost::dll::library_info inf("libsotest.so");
std::vector<std::string> s = inf.sections();
auto found = (std::find(s.begin(), s.end(), "MySect") != s.end());
std::cout << "Found: " << std::boolalpha << found << "\n";
}
Prints:
In fact, I cannot compile it at all when the section name exceeds 9 characters:
test.cpp|11 col 1| error: static assertion failed: Some platforms require section names to be at most 8 bytes
|| 11 | BOOST_DLL_ALIAS_SECTIONED(
Perhaps your problem is related to such restrictions?
I want to create a loadable DLL of some of my tcl methods. But I am not getting how to do this. For that I have taken a simple example of tcl api which adds two numbers and prints the sum. Now I want to create a loadable DLL for this to export this tcl functionality.
But I am not understanding how to do it in Visual Studio. I have written a C code which can call this tcl api and get the sum of two integers, but again I don't want it to do this way. I want to create a DLL file to use this tcl functionality. How can I create this DLL on Visual Studio 2010.
Below is my sample tcl program that I am using:
#!/usr/bin/env tclsh8.5
proc add_two_nos { } {
set a 10
set b 20
set c [expr { $a + $b } ]
puts " c is $c ......."
}
And here is the C code which can use this tcl functionality :
#include <tcl.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
Tcl_Interp *interp;
int code;
char *result;
Tcl_FindExecutable(argv[0]);
interp = Tcl_CreateInterp();
code = Tcl_Eval(interp, "source myscript.tcl; add_two_nos");
/* Retrieve the result... */
result = Tcl_GetString(Tcl_GetObjResult(interp));
/* Check for error! If an error, message is result. */
if (code == TCL_ERROR) {
fprintf(stderr, "ERROR in script: %s\n", result);
exit(1);
}
/* Print (normal) result if non-empty; we'll skip handling encodings for now */
if (strlen(result)) {
printf("%s\n", result);
}
/* Clean up */
Tcl_DeleteInterp(interp);
exit(0);
}
I have successfully compiled this code with the below command
gcc simple_addition_wrapper_new.c -I/usr/include/tcl8.5/ -ltcl8.5 -o simple_addition_op
The above code is working with the expected output.
What steps do I need to take to create a loadable dll for this in Visual Studio 2010?
If you look at the answers to this question: here it gives the basic outline of the process you need to go through. There are links from my answer to some Microsoft MSDN articles on creating DLLs.
To go into this in a little more detail for a C++ dll that has Tcl embedded in it.
The first step is to create a new visual studio project with the correct type, one that is going to build a dll that exports symbols. My example project is called TclEmbeddedInDll and that name appears in code in symbols such as TCLEMBEDDEDINDLL_API that are generated by Visual Studio.
The dllmain.cpp look like this:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
allocInterp() ;
break ;
}
case DLL_THREAD_ATTACH:
break ;
case DLL_THREAD_DETACH:
break ;
case DLL_PROCESS_DETACH:
{
destroyInterp() ;
break;
}
}
return TRUE;
}
The allocInterp() and destroyInterp() functions are defined in the TclEmbeddedInDll.h, the reason for using functions here rather than creating the Tcl_Interp directly is that it keeps the details about Tcl away from the DLL interface. If you create the interp here then you have to include tcl.h and then things get complicated when you try and use the DLL in another program.
The TclEmbeddedInDll.h and .cpp are shown next, the function fnTclEmbeddedInDll() is the one that is exported from the DLL - I'm using C linkage for this rather than C++ as it makes it easier to call the function from other languages IMHO.
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the TCLEMBEDDEDINDLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// TCLEMBEDDEDINDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef TCLEMBEDDEDINDLL_EXPORTS
#define TCLEMBEDDEDINDLL_API __declspec(dllexport)
#else
#define TCLEMBEDDEDINDLL_API __declspec(dllimport)
#endif
extern "C" {
TCLEMBEDDEDINDLL_API void fnTclEmbeddedInDll(void);
}
void allocInterp() ;
void destroyInterp() ;
// TclEmbeddedInDll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
extern "C" {
static Tcl_Interp *interp ;
// This is an example of an exported function.
TCLEMBEDDEDINDLL_API void fnTclEmbeddedInDll(void)
{
int code;
const char *result;
code = Tcl_Eval(interp, "source simple_addition.tcl; add_two_nos");
result = Tcl_GetString(Tcl_GetObjResult(interp));
}
}
void allocInterp()
{
Tcl_FindExecutable(NULL);
interp = Tcl_CreateInterp();
}
void destroyInterp()
{
Tcl_DeleteInterp(interp);
}
The implementation of allocInterp() and destroyInterp() is very naive, no error checking is done.
Finally for the Dll the stdafx.h file ties it all together like this:
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
// TODO: reference additional headers your program requires here
#include <tcl.h>
#include "TclEmbeddedInDll.h"
I'm getting the following:
Unknown type name 'mach_port_context_t'
As a compiler error when I'm trying to build my XCode project. It points to message.h, which is in the iPhoneSimulator5.1/usr/include/mach/ folder.
It doesn't show up when I build for the device. (I'm testing in simulator b/c I need to debug some files)
I'm definitely not doing any crazy threading or port stuff (outside of NSOperation), so I'm not sure what the issue for the mach is...
mach_port_context_t has no definition in message.h file... others such as audit_token_t and security_token_t do:
typedef struct
{
mach_msg_trailer_type_t msgh_trailer_type;
mach_msg_trailer_size_t msgh_trailer_size;
mach_port_seqno_t msgh_seqno;
security_token_t msgh_sender; // <-- defined (ex. below)
audit_token_t msgh_audit; //<-- defined (ex. below)
mach_port_context_t msgh_context; //<-- Error Here
} mach_msg_context_trailer_t;
typedef struct
{
unsigned int val[8];
} audit_token_t;
typedef struct
{
unsigned int val[2];
} security_token_t;
Help?
clear project "User Header Search Path"
I have a .dll I suspect uses __stdcall functions, but totally undecorated names (not even an underscore or # sign). I wrote a .def file for it with aliases like
func1 = func1
func1#4 = func1
but I think lib (which I am using to create the import library from the .def file) is ignoring the aliases (the linker still says func1#4 is undefined)
How can I create an import library that will map func1#4 to func1?
I don't know if it possible to create right .lib file with lib.exe, so I suggest to create a DLL with stubs of functions exported by original DLL.
Example dll.cpp file:
void __stdcall foo(int) {}
dll.def file:
EXPORTS
foo=foo
Then you compile it, from IDE, or command line:
cl dll.cpp /link /dll /def:dll.def /noentry
It will create correct dll.lib file, so you can use it with code like this:
void __stdcall foo(int);
#pragma comment(lib, "dll")
int main()
{
foo(42);
}
You should be declaring the function prototype as extern "C" as you are (obviously) compiling with in C++ mode:
extern "C" void func1(void); // correct prototype, add __stdcall if necessary?
You can wrap entire sections of a header file inside
extern "C" {
// ... C compatible declarations
}