EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: epicsExportShared symbols
From: Michael Davidsaver via Core-talk <core-talk at aps.anl.gov>
To: Mark Rivers <rivers at cars.uchicago.edu>, "'Johnson, Andrew N.'" <anj at anl.gov>
Cc: 'EPICS core-talk' <core-talk at aps.anl.gov>
Date: Sun, 30 Aug 2020 16:27:54 -0700
> -epicsShareExtern asynManager *pasynManager;
> 
> +ASYN_API asynManager *pasynManager;

The ASYN_API macro doesn't contain 'extern'.  Try:

> +ASYN_API extern asynManager *pasynManager;


On 8/30/20 4:10 PM, Mark Rivers wrote:
> Only 3 object files report the multiply defined symbols: paramVal, asynPortDriver, and asynPortClient.  The thing those files have in common it that they are C++ not C.  C files don’t have that error.
> 
>  
> 
> Mark
> 
>  
> 
>  
> 
> *From:*Mark Rivers
> *Sent:* Sunday, August 30, 2020 5:52 PM
> *To:* 'Johnson, Andrew N.' <anj at anl.gov>
> *Cc:* EPICS core-talk <core-talk at aps.anl.gov>; Michael Davidsaver <mdavidsaver at gmail.com>
> *Subject:* RE: epicsExportShared symbols
> 
>  
> 
> Hi Andrew,
> 
>  
> 
> I’m starting to make the change to use ASYN_API in asyn.  I’m having a problem with pasynTrace and pasynManager being multiply defined:
> 
>  
> 
> paramVal.o:(.bss+0x0): multiple definition of `pasynTrace'
> 
> asynManager.o:(.data.rel.local+0x230): first defined here
> 
> paramVal.o:(.bss+0x8): multiple definition of `pasynManager'
> 
> asynManager.o:(.data.rel.local+0x240): first defined here
> 
> asynPortDriver.o:(.bss+0x0): multiple definition of `pasynTrace'
> 
> asynManager.o:(.data.rel.local+0x230): first defined here
> 
> asynPortDriver.o:(.bss+0x10): multiple definition of `pasynManager'
> 
> asynManager.o:(.data.rel.local+0x240): first defined here
> 
> asynPortClient.o:(.bss+0x10): multiple definition of `pasynManager'
> 
> asynManager.o:(.data.rel.local+0x240): first defined here
> 
> asynPortClient.o:(.bss+0x0): multiple definition of `pasynTrace'
> 
> asynManager.o:(.data.rel.local+0x230): first defined here
> 
> collect2: error: ld returned 1 exit status
> 
> make[1]: *** [libasyn.so] Error 1
> 
> make[1]: Leaving directory `/home/epics/devel/asyn-4-40/asyn/O.linux-x86_64'
> 
>  
> 
>  
> 
> This is what I have changed.  It seems like I am doing things correctly, except that I was not sure what I should replace epicsShareDef with.  I just deleted it.
> 
>  
> 
>  
> 
> corvette:~/devel/asyn/asyn>git diff
> 
> diff --git a/asyn/Makefile b/asyn/Makefile
> 
> index c4c6254..0ecfecc 100644
> 
> --- a/asyn/Makefile
> 
> +++ b/asyn/Makefile
> 
> @@ -354,3 +354,9 @@ else
> 
>         @$(MV) $(notdir $@) $@
> 
> endif
> 
>  
> 
> +$(LIB_PREFIX)asyn$(LIB_SUFFIX): USR_CPPFLAGS += -DBUILDING_asyn_API
> 
> +ifeq ($(SHARED_LIBRARIES),YES)
> 
> +  $(SHRLIB_PREFIX)asyn$(SHRLIB_SUFFIX): USR_CPPFLAGS += -DBUILDING_asyn_API
> 
> +endif
> 
> +
> 
> +
> 
> diff --git a/asyn/asynDriver/asynDriver.h b/asyn/asynDriver/asynDriver.h
> 
> index f1397e7..b376e8b 100644
> 
> --- a/asyn/asynDriver/asynDriver.h
> 
> +++ b/asyn/asynDriver/asynDriver.h
> 
> @@ -20,6 +20,7 @@
> 
> #include <ellLib.h>
> 
> #include <shareLib.h>
> 
> #include <epicsVersion.h>
> 
> +#include <asynAPI.h>
> 
>  
> 
> /* Version number names similar to those provide by base
> 
>   * These macros are always numeric */
> 
> @@ -184,7 +185,7 @@ typedef struct asynManager {
> 
>  
> 
>      const char *(*strStatus)(asynStatus status);
> 
> }asynManager;
> 
> -epicsShareExtern asynManager *pasynManager;
> 
> +ASYN_API asynManager *pasynManager;
> 
>  
> 
> /* Interface supported by ALL asyn drivers*/
> 
> #define asynCommonType "asynCommon"
> 
> @@ -273,7 +274,7 @@ typedef struct asynTrace {
> 
>                      const char *buffer, size_t len,const char *file, int line, const char *pformat, va_list pvar) EPICS_PRINTF_STYLE(7,0);
> 
> #endif
> 
> }asynTrace;
> 
> -epicsShareExtern asynTrace *pasynTrace;
> 
> +ASYN_API asynTrace *pasynTrace;
> 
>  
> 
> #if (defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L) || defined(_WIN32)
> 
> #define asynPrint(pasynUser,reason, ...) \
> 
> diff --git a/asyn/asynDriver/asynManager.c b/asyn/asynDriver/asynManager.c
> 
> index ac1b9b6..c94a2ab 100644
> 
> --- a/asyn/asynDriver/asynManager.c
> 
> +++ b/asyn/asynDriver/asynManager.c
> 
> @@ -386,7 +386,7 @@ static asynManager manager = {
> 
>      setTimeStamp,
> 
>      strStatus
> 
> };
> 
> -epicsShareDef asynManager *pasynManager = &manager;
> 
> +asynManager *pasynManager = &manager;
> 
>  
> 
> /* asynTrace methods */
> 
> static asynStatus traceLock(asynUser *pasynUser);
> 
> @@ -439,7 +439,7 @@ static asynTrace asynTraceManager = {
> 
>      traceVprintIO,
> 
>      traceVprintIOSource
> 
> };
> 
> -epicsShareDef asynTrace *pasynTrace = &asynTraceManager;
> 
> +asynTrace *pasynTrace = &asynTraceManager;
> 
>  
> 
> /*internal methods */
> 
> static void tracePvtInit(tracePvt *ptracePvt)
> 
> diff --git a/asyn/asynPortDriver/asynPortDriver.cpp b/asyn/asynPortDriver/asynPortDriver.cpp
> 
> index 3569d93..822f552 100644
> 
> --- a/asyn/asynPortDriver/asynPortDriver.cpp
> 
> +++ b/asyn/asynPortDriver/asynPortDriver.cpp
> 
> @@ -27,8 +27,6 @@
> 
>      #include <dbAccess.h>
> 
> #endif
> 
>  
> 
> -#define epicsExportSharedSymbols
> 
> -#include <shareLib.h>
> 
> #include "paramVal.h"
> 
> #include "paramErrors.h"
> 
> #include "asynParamType.h"
> 
> diff --git a/asyn/asynPortDriver/asynPortDriver.h b/asyn/asynPortDriver/asynPortDriver.h
> 
> index b7ae8e7..5d175f8 100644
> 
> --- a/asyn/asynPortDriver/asynPortDriver.h
> 
> +++ b/asyn/asynPortDriver/asynPortDriver.h
> 
> @@ -15,7 +15,7 @@
> 
>  
> 
> class paramList;
> 
>  
> 
> -epicsShareFunc void* findAsynPortDriver(const char *portName);
> 
> +ASYN_API void* findAsynPortDriver(const char *portName);
> 
> typedef void (*userTimeStampFunction)(void *userPvt, epicsTimeStamp *pTimeStamp);
> 
>  
> 
> #ifdef __cplusplus
> 
> @@ -42,7 +42,7 @@ class callbackThread;
> 
>  
> 
> /** Base class for asyn port drivers; handles most of the bookkeeping for writing an asyn port driver
> 
>    * with standard asyn interfaces and a parameter library. */
> 
> -class epicsShareClass asynPortDriver {
> 
> +class ASYN_API asynPortDriver {
> 
> public:
> 
>      asynPortDriver(asynParamSet* paramSet,
> 
>                     const char *portName, int maxAddr, int interfaceMask, int interruptMask,
> 
>  
> 
>  
> 
> Thanks,
> 
> Mark
> 
>  
> 
>  
> 
>  
> 
> *From:*Johnson, Andrew N. <anj at anl.gov <mailto:anj at anl.gov>>
> *Sent:* Tuesday, August 11, 2020 12:46 PM
> *To:* Mark Rivers <rivers at cars.uchicago.edu <mailto:rivers at cars.uchicago.edu>>
> *Cc:* EPICS core-talk <core-talk at aps.anl.gov <mailto:core-talk at aps.anl.gov>>; Michael Davidsaver <mdavidsaver at gmail.com <mailto:mdavidsaver at gmail.com>>
> *Subject:* Re: epicsExportShared symbols
> 
>  
> 
> Hi Mark,
> 
>  
> 
> The _API pattern is probably simpler overall, but it does need a separate header file for each DLL. The makeAPIheader.pl script explains how to use it, just run it with a -h flag for instructions.
> 
>  
> 
> Since you’re looking tor this to work with older versions of Base though I suggest you run the makeAPIheader.pl script by hand from Base-7.0.4 to create each *API.h file but then add the output file to your repo in the appropriate Makefile and directory. You should /not/ set the API_HEADER or *_API variables in that Makefile though as the help text suggests.
> 
>  
> 
> The other part is that you need to add some rules to the end of the Makefile where the library gets built, which I think for asyn would be this:
> 
>  
> 
> $(LIB_PREFIX)asyn$(LIB_SUFFIX): USR_CPPFLAGS += -DBUILDING_asyn_API
> 
> ifeq ($(SHARED_LIBRARIES),YES)
> 
>   $(SHRLIB_PREFIX)asyn$(SHRLIB_SUFFIX): USR_CPPFLAGS += -DBUILDING_asyn_API
> 
> endif
> 
>  
> 
> I’m not sure if the LIB_PREFIX line is needed or not, but it won’t do any harm. If you were building a loadable library you’d need to add another line as well, but that’s only for creating plugins for other tools or languages.
> 
>  
> 
> HTH,
> 
>  
> 
> - Andrew
> 
>  
> 
>  
> 
>     On Aug 11, 2020, at 11:27 AM, Michael Davidsaver <mdavidsaver at gmail.com <mailto:mdavidsaver at gmail.com>> wrote:
> 
>      
> 
>     On 8/11/20 9:06 AM, Mark Rivers wrote:
> 
>         I note that in the comments at the beginning of shareLib.h in base 7.0.4 says that this construct is deprecated:
> 
>         *     #ifdef epicsExportSharedSymbols
>         *     #   define interfacePDQ_epicsExportSharedSymbols
>         *     #   undef epicsExportSharedSymbols
>         *     #endif
>         *
>         *     #include "epicsTypes.h"
>         *     #include "epicsTime.h"
>         *
>         *     #ifdef interfacePDQ_epicsExportSharedSymbols
>         *     #   define epicsExportSharedSymbols
>         *     #   include "shareLib.h"
>         *     #endif
>         *
>         *     epicsShareFunc int myExtFunc ( int arg );
>         *     epicsShareExtern int myExtVar;
>         *     class epicsShareClass myClass {};mechanism being used in pvAccess, 
> 
>         However, that construct is still used in pvAccess, pvDatabase, normativeTypes, and pvaClient.
> 
>         It seems to me that this construct has an advantage over the one that is preferred in shareLib.h.  
> 
>         Let's say I add a new dependency on EPICS base to myClass.h, for example epicsMutex.h.  It seems to me that with the preferred mechanism I must modify all .cpp files that include myClass.h to first include epicsMutex.h before defining epicsExportSharedSymbols and including myClass.h.  Otherwise myClass.h will end up exporting epicsMutex functions.  With the deprecated mechanism this is not necessary, and my .cpp files don't even need to include epicsMutex.h at all.
> 
>         Am I missing something?
> 
> 
>     The undef epicsExportSharedSymbols pattern can work, if you're consistent.
>     Unfortunately, working as I do primarily on Linux, where there is no need
>     to be consistent, it is easy for ordering issues to slip in.  And I find
>     sorting them out to be quite tedious.
> 
>     If you prefer the *_API pattern, then you don't need to worry about these
>     sort of header ordering issues.  This entire class of potential problems
>     is avoided.
> 
>     eg. I started this way with my new PVXS module, and have had a much easier
>     time in porting to Windows.  No mysterious missing symbols showing up in
>     my appveyor builds.
> 
> 
>         Mark
> 
>         -----Original Message-----
>         From: Michael Davidsaver <mdavidsaver at gmail.com <mailto:mdavidsaver at gmail.com>> 
>         Sent: Tuesday, August 11, 2020 9:29 AM
>         To: Mark Rivers <rivers at cars.uchicago.edu <mailto:rivers at cars.uchicago.edu>>; Johnson, Andrew N. <anj at anl.gov <mailto:anj at anl.gov>>
>         Cc: core-talk at aps.anl.gov <mailto:core-talk at aps.anl.gov>
>         Subject: Re: epicsExportShared symbols
> 
>         On 8/11/20 6:18 AM, Mark Rivers via Core-talk wrote:
> 
>             Hi Andrew,
> 
> 
>             I am trying to figure out the best way to clean up my code (asyn, areaDetector, etc.) to handle the __declspec DLL_EXPORT/IMPORT stuff.
> 
> 
>             I posted a comment to this thread in ADCore about it just now:
> 
>             https://github.com/areaDetector/ADCore/issues/455#issuecomment-6719337
>             86
> 
> 
>             It looks like EPICS base 7.0.4 has 2 ways of doing it, for example using LIBCOM_API/LIBCA_API, or the more traditional epicsShareFunc and epicsExportSharedSymbols (e.g. in pvAccess).
> 
> 
>             I did a "git grep LIBCOM_API" and I cannot actually figure out where LIBCOM_API is defined and how that mechanism works.  Can you explain?
> 
> 
>             Does the LIBCA_API mechanism rely on anything in base 7, or can it be used with older versions of base?
> 
> 
>         Since the _API macros are my initiative, I'll answer this one.
>         For a support module, you might be better to start looking at the pva2pva module, which is where I tried the idea before changing Base.
> 
>         https://github.com/epics-base/pva2pva/blob/master/pdbApp/pv/qsrv.h#L21-L37
> 
>         With Base 7.0.4, this sort of header is generated by makeAPIheader.pl to avoid repetition. This did involve some Makefile changes to account for dependency issues with use of a generated header by basically every object file.
> 
>         https://github.com/epics-base/epics-base/blob/7.0/src/tools/makeAPIheader.pl
> 
>  
> 
> -- 
> 
> Complexity comes for free, simplicity you have to work for.
> 
>  
> 


Replies:
RE: epicsExportShared symbols Mark Rivers via Core-talk
References:
epicsExportShared symbols Mark Rivers via Core-talk
Re: epicsExportShared symbols Michael Davidsaver via Core-talk
RE: epicsExportShared symbols Mark Rivers via Core-talk
Re: epicsExportShared symbols Michael Davidsaver via Core-talk
Re: epicsExportShared symbols Johnson, Andrew N. via Core-talk
RE: epicsExportShared symbols Mark Rivers via Core-talk
RE: epicsExportShared symbols Mark Rivers via Core-talk

Navigate by Date:
Prev: RE: epicsExportShared symbols Mark Rivers via Core-talk
Next: RE: epicsExportShared symbols Mark Rivers via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024 
Navigate by Thread:
Prev: RE: epicsExportShared symbols Mark Rivers via Core-talk
Next: RE: epicsExportShared symbols Mark Rivers via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024 
ANJ, 30 Aug 2020 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·