epics-modules / asyn

EPICS module for driver and device support
http://epics-modules.github.io/asyn/
Other
37 stars 75 forks source link

Define asyn_SYS_LIBS* in a way that dependent drivers can find it #141

Open dirk-zimoch opened 3 years ago

dirk-zimoch commented 3 years ago

Under some circumstances, drivers dependent on asyn seemingly require to link with the same SYS_LIBS as asyn. At least that‘s what some StreamDevice users tell me. But how should those drivers know when asyn_SYS_LIBS is only defined in the asyn Makefile? It would be nice to have some macro like $(EPICS_BASE_IOC_LIBS) for asyn too. Can asyn_SYS_LIBS be defined in a file that other Makefiles can include?

MarkRivers commented 3 years ago

That seems like a nice idea, but I am not sure how to implement it.

$(EPICS_BASE_IOC_LIBS) is quite simple because it is never dependent on EPICS_HOST_ARCH nor on site-specific packages. It is just defined here:

/usr/local/epics-devel/base-7.0.6/configure/CONFIG_DATABASE_MODULE:EPICS_BASE_IOC_LIBS = dbRecStd dbCore ca Com

asyn on the other hand uses SYS_LIBS that are dependent on EPICS_HOST_ARCH and on whether certain packages are installed or not. It starts with the contents of CONFIG_SITE:

# If you have the local Linux GPIB support installed (http://sourceforge.net/projects/linux-gpib/)
# then set LINUX_GPIB=YES
LINUX_GPIB=NO

# If you have libusb-1.0 revision 16 or newer and want the USB TMC support set DRV_USBTMC=YES
#DRV_USBTMC=YES

# You can also define this on a per-architecture basis.
# In this example DRV_USBTMC would be built only for linux-x86_64, and not for other architectures
#ifeq (linux-x86_64, $(T_A))
#  DRV_USBTMC=YES
#endif

# If you have libusb-1.0 and libftdi, and want FTDI support, set DRV_FTDI=YES
DRV_FTDI=NO

# If your system has libftdi1, set the following to YES. If it has libftdi, set it to NO
DRV_FTDI_USE_LIBFTDI1=NO

# If you want to build asyn so the only dependency on EPICS base is libCom then set the following flag
#EPICS_LIBCOM_ONLY=YES

# Some linux systems moved RPC related symbols to libtirpc
# To enable linking against this library, uncomment the following line
# TIRPC=YES

and then these variables are used in asyn/Makefile to define SYS_LIBS:

corvette:~/devel/asyn/asyn>grep -U10 SYS_LIBS Makefile
LIBRARY_IOC += asyn

asyn_SYS_LIBS_WIN32 = ws2_32 winmm
asyn_SYS_LIBS_cygwin32 = $(CYGWIN_RPC_LIB)

# Some linux systems moved RPC related symbols to libtirpc
# Define TIRPC in configure/CONFIG_SITE in this case
ifeq ($(TIRPC),YES)
  USR_INCLUDES_Linux += -I/usr/include/tirpc
  asyn_SYS_LIBS_Linux += tirpc
endif
--

ifneq (, $(findstring RTEMS, $(T_A)))
  DRV_USBTMC = NO
endif
ifneq (, $(findstring vxWorks, $(T_A)))
  DRV_USBTMC = NO
endif
ifeq ($(DRV_USBTMC),YES)
  SRC_DIRS += $(ASYN)/drvAsynUSBTMC
  asyn_SRCS += drvAsynUSBTMC.c
  asyn_SYS_LIBS += usb-1.0
  DBD += drvAsynUSBTMC.dbd
endif

ifeq ($(DRV_FTDI),YES)
  SRC_DIRS += $(ASYN)/drvAsynFTDI
  asyn_SRCS += ftdiDriver.cpp drvAsynFTDIPort.cpp
  asyn_SYS_LIBS += usb-1.0
  INC += drvAsynFTDIPort.h
  ifeq ($(DRV_FTDI_USE_LIBFTDI1),YES)
    asyn_SYS_LIBS += ftdi1
    USR_CXXFLAGS += -DHAVE_LIBFTDI1
  else
    asyn_SYS_LIBS += ftdi
  endif
  DBD += drvAsynFTDIPort.dbd
endif

ifeq ($(LINUX_GPIB),YES)
  SRC_DIRS += $(ASYN)/linuxGpib
  asyn_SRCS_Linux += drvLinuxGpib.c
  DBD += drvLinuxGpib.dbd
  asyn_SYS_LIBS += gpib
endif

There would thus need to be a configuration file that defined these for each EPICS_HOST_ARCH, and that configuration file would need to available to other modules that depend on asyn.

anjohnson commented 3 years ago

Asyn can install a CFG file CONFIG_ASYN_MODULE which every downstream application will include automatically when its RELEASE file contains a pointer to Asyn. Then for each target it builds, Asyn would also create a CFG file say ASYN.$(EPICS_HOST_ARCH).$(T_A) which the first file would include like this:

# CONFIG_ASYN_MODULE

ifneq ($(T_A),)
  include $(ASYN)/cfg/ASYN.$(EPICS_HOST_ARCH).$(T_A)
endif

The Asyn build knows how it has been configured for its specific host+target combination, so the ASYN.* files that get created don't need any conditionals in them at all, they just set the variables that will be needed to build IOCs for that particular target, e.g:

# ASYN.centos8-x86_64.centos8-x86_64

asyn_IOC_LIBS += asyn
asyn_SYS_LIBS += tirpc
asyn_SYS_LIBS += usb-1.0
asyn_SYS_LIBS += ftdi1

Note that there's no need to set USR_INCLUDES since that's only needed when compiling code inside Asyn. If you publish optional DBD files they should be added to something like asyn_DBD; the idea is that the Makefile which builds the IOC must explicitly use the variables defined in the above file, since other targets might not want to link against those libraries.

MarkRivers commented 3 years ago

I'm not clear on how having asyn_SYS_LIBS defined to include those system libraries helps when I am building an IOC. Do I do the following in my IOC Makefile?

PROD_SYS_LIBS += asyn_SYS_LIBS
anjohnson commented 3 years ago

Almost:

PROD_LIBS += $(asyn_IOC_LIBS)
PROD_LIBS += $(EPICS_BASE_IOC_LIBS)
PROD_SYS_LIBS += $(asyn_SYS_LIBS)

This can obviously be extended to other modules too, say

PROD_LIBS += $(modbus_IOC_LIBS)
PROD_LIBS += $(asyn_IOC_LIBS)
PROD_LIBS += $(EPICS_BASE_IOC_LIBS)
PROD_SYS_LIBS += $(asyn_SYS_LIBS)

I don't think modbus_IOC_LIBS should include $(asyn_IOC_LIBS) though, I think the IOC's Makefile should have to explicitly mention every module that it wants to be linked against.

One thing we have to be careful of with these names though is that the variable asyn_SYS_LIBS is also the prod-specific *_SYS_LIBS variable that would be used when linking a PROD called asyn, which might cause problems. Maybe I should have suggested the upper-case ASYN_SYS_LIBS for that variable, or the name asyn_IOC_SYS_LIBS instead (or even combine the two to make ASYN_IOC_SYS_LIBS).