vvp: build and install libvvp as a versioned shared library

It uses a dedicated LIBVVP_SOVERSION specified in onfigure.ac
for the SONAME and full library version.

For linking, a pkg-config file is generated, and when building on
Windows, an import library is created that can be used with both
GCC and MSVC compilers.

On non-Windows platforms, all object files are compiled with -fPIC
to ensure compatibility with shared libraries.

On Windows use 'lib' prefix for library name with MinGW compiler
only. Other compiler like MSVC normally are not using any library
prefix.

With this commit the build rules for the vpp executable has been
cleaned too because the complex structure of the manually created
Makefile.in made it very difficult to extract specific parts of
them.
This commit is contained in:
Ralf Habacker 2026-04-27 07:08:29 +02:00
parent 4014db47e0
commit 9d3101fd19
4 changed files with 157 additions and 60 deletions

View File

@ -145,20 +145,8 @@ endif
check: all
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true
test -r check.conf || cp $(srcdir)/check.conf .
driver/iverilog -B. -BMvpi -BPivlpp -tcheck -ocheck.vvp $(srcdir)/examples/hello.vl
ifeq (@WIN32@,yes)
ifeq (@install_suffix@,)
vvp/vvp -M- -M./vpi ./check.vvp | grep 'Hello, World'
else
# On Windows if we have a suffix we must run the vvp part of
# the test with a suffix since it was built/linked that way.
ln vvp/vvp.exe vvp/vvp$(suffix).exe
vvp/vvp$(suffix) -M- -M./vpi ./check.vvp | grep 'Hello, World'
rm vvp/vvp$(suffix).exe
endif
else
$(ENV_VVP) vvp/vvp -M- -M./vpi ./check.vvp | grep 'Hello, World'
endif
driver/iverilog@EXEEXT@ -B. -BMvpi -BPivlpp -tcheck -ocheck.vvp $(srcdir)/examples/hello.vl
$(ENV_VVP) vvp/vvp$(suffix)@EXEEXT@ -M- -M./vpi ./check.vvp | grep 'Hello, World'
check-installed check-installed-vpi check-installed-vvp check-installed-vvp-py:
$(MAKE) -C ivtest $@

View File

@ -7,6 +7,9 @@ m4_define([VER_MAJOR], [14])
m4_define([VER_MINOR], [0])
m4_define([VER_EXTRA], [devel])
dnl define libvvp ABI version
m4_define([LIBVVP_SOVERSION], [1])
AC_INIT([iverilog], [VER_MAJOR.VER_MINOR (VER_EXTRA)])
AC_SUBST([VERSION_MAJOR], [VER_MAJOR])
AC_SUBST([VERSION_MINOR], [VER_MINOR])
@ -15,6 +18,11 @@ AC_SUBST([VERSION], ["VER_MAJOR.VER_MINOR (VER_EXTRA)"])
# used in res.rc
AC_SUBST([PRODUCTVERSION], ["VER_MAJOR,VER_MINOR,0,0"])
# setup libvvp soversion, which depends on abi not package version
AC_SUBST([LIBVVP_SOVERSION], [LIBVVP_SOVERSION])
# setup libvvp version
AC_SUBST([LIBVVP_VERSION], [LIBVVP_SOVERSION.VER_MAJOR.VER_MINOR])
AC_CONFIG_SRCDIR([netlist.h])
# Need a stamp file like the other header files
AC_CONFIG_FILES([version_base.h],[
@ -209,7 +217,14 @@ AC_FUNC_FSEEKO
# Build VVP as a library and stub
AC_ARG_ENABLE([libvvp],
[AS_HELP_STRING([--enable-libvvp], [build VVP as a shared library])],
[AC_SUBST(LIBVVP, yes)],[])
[enable_libvvp=yes],
[enable_libvvp=no])
AC_SUBST([LIBVVP], [$enable_libvvp])
AS_IF([test "x$enable_libvvp" = "xyes"],
[AC_MSG_NOTICE([Building with libvvp support enabled])],
[AC_MSG_NOTICE([Building with libvvp support disabled])])
AC_ARG_ENABLE([libveriuser],
[AS_HELP_STRING([--enable-libveriuser], [include support for PLI 1 (deprecated)])],
@ -434,6 +449,7 @@ AC_CONFIG_FILES([
vhdlpp/Makefile
vpi/Makefile
vvp/Makefile
vvp/libvvp.pc
vvp/vvp.man
])
AC_OUTPUT

View File

@ -23,6 +23,7 @@ prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
datarootdir = @datarootdir@
abs_builddir = @abs_builddir@
VPATH = $(srcdir)
@ -30,6 +31,8 @@ bindir = @bindir@
libdir = @libdir@
man1dir = @mandir@/man1
docdir = @docdir@
pkgconfigdir = @libdir@/pkgconfig
# This is actually the directory where we install our own header files.
# It is a little different from the generic includedir.
ivl_includedir = @includedir@/iverilog$(suffix)
@ -58,17 +61,80 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/..
endif
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -DICARUS_VPI_CONST=const
CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@
CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@
LDFLAGS = @rdynamic@ @LDFLAGS@
CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ @PICFLAG@
CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ @PICFLAG@
LDFLAGS = @rdynamic@ @LDFLAGS@ @PICFLAG@
LIBS = @LIBS@ @EXTRALIBS@ @DLLIB@
ifeq (@WIN32@,yes)
LIBVVP_VERSION = @LIBVVP_VERSION@
LIBVVP_SOVERSION = @LIBVVP_SOVERSION@
LIBBASENAME=vvp$(suffix)
LDFLAGS_SHARED = @rdynamic@ @shared@ @LDFLAGS@
ifeq (@MINGW32@,yes)
SLDIR=$(bindir)
SLEXT=dll
IMPEXT=dll.a
LIBPREFIX=lib
LIBNAME=$(LIBPREFIX)$(LIBBASENAME)
LIBSONAME=$(LIBNAME).$(SLEXT).$(LIBVVP_SOVERSION)
LIBREALNAME=$(LIBNAME).$(SLEXT).$(LIBVVP_VERSION)
LIBLINKNAME=$(LIBNAME).$(SLEXT)
LIBTARGET=$(LIBNAME)-$(LIBVVP_SOVERSION).$(SLEXT)
LIBBUILD=$(LIBTARGET)
LIBLINKFLAGS=-Wl,--out-implib,$(LIBNAME).$(IMPEXT) -Wl,--no-undefined
LIBPOSTBUILD=@true
LIBINSTALL=$(LIBTARGET)
LIBDEVELINSTALL=$(LIBNAME).$(IMPEXT)
else ifeq (@WIN32@,yes)
SLDIR=$(bindir)
SLEXT=dll
IMPEXT=lib
LIBPREFIX=
LIBNAME=$(LIBPREFIX)$(LIBBASENAME)
LIBSONAME=$(LIBNAME).$(SLEXT).$(LIBVVP_SOVERSION)
LIBREALNAME=$(LIBNAME).$(SLEXT).$(LIBVVP_VERSION)
LIBLINKNAME=$(LIBNAME).$(SLEXT)
LIBTARGET=$(LIBLINKNAME)
LIBBUILD=$(LIBLINKNAME)
LIBLINKFLAGS=
LIBPOSTBUILD=@true
LIBINSTALL=$(LIBTARGET)
LIBDEVELINSTALL=
else ifneq (,$(findstring darwin,@host_os@))
SLDIR=$(libdir)
SLEXT=dylib
LIBPREFIX=lib
LIBNAME=$(LIBPREFIX)$(LIBBASENAME)
LIBSONAME=$(LIBNAME).$(LIBVVP_SOVERSION).$(SLEXT)
LIBREALNAME=$(LIBNAME).$(LIBVVP_VERSION).$(SLEXT)
LIBLINKNAME=$(LIBNAME).$(SLEXT)
LIBTARGET=$(LIBREALNAME)
LIBBUILD=$(LIBTARGET)
LDFLAGS_SHARED=-dynamiclib
LIBLINKFLAGS= \
-Wl,-install_name,$(libdir)/$(LIBSONAME) \
-Wl,-compatibility_version,$(LIBVVP_SOVERSION) \
-Wl,-current_version,$(LIBVVP_VERSION)
LIBPOSTBUILD= \
ln -sf $(LIBREALNAME) $(LIBSONAME) && \
ln -sf $(LIBSONAME) $(LIBLINKNAME)
LIBINSTALL=$(LIBTARGET)
LIBDEVELINSTALL=
else
SLDIR=$(libdir)
SLEXT=so
LIBPREFIX=lib
LIBNAME=$(LIBPREFIX)$(LIBBASENAME)
LIBSONAME=$(LIBNAME).$(SLEXT).$(LIBVVP_SOVERSION)
LIBREALNAME=$(LIBNAME).$(SLEXT).$(LIBVVP_VERSION)
LIBLINKNAME=$(LIBNAME).$(SLEXT)
LIBTARGET=$(LIBREALNAME)
LIBBUILD=$(LIBLINKNAME)
LIBLINKFLAGS=-Wl,-soname,$(LIBSONAME)
LIBPOSTBUILD=ln -sf $(LIBREALNAME) $(LIBSONAME) && ln -sf $(LIBSONAME) $(LIBLINKNAME)
LIBINSTALL=$(LIBTARGET)
LIBDEVELINSTALL=
endif
MDIR1 = -DMODULE_DIR1='"$(libdir)/ivl$(suffix)"'
@ -91,27 +157,37 @@ VPI_OBJ = vpi_modules.o vpi_bit.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_d
vpip_to_dec.o vpip_format.o vvp_vpi.o
LIB_OBJ = $(CORE_OBJ) $(VPI_OBJ)
LIB_CLEAN = $(LIBNAME)*.$(SLEXT)* libvvp.pc
VVP_OBJ = main.o
VVP_CLEAN = vvp@EXEEXT@
ifeq (@WIN32@,yes)
# To support cocotb, we export the VPI functions directly. This allows
# cocotb to build VPI modules without using our vpi_user.h and libvpi.a.
# The .def file controls what is exported.
VVP_OBJ += $(srcdir)/vvp.def
endif
ifeq (@LIBVVP@,yes)
VVP_LDFLAGS = -lvvp$(suffix)
VVP_DEPS = $(LIBBUILD)
else
VVP_OBJ += $(LIB_OBJ)
endif
ifneq (@install_suffix@,)
VVP_POSTBUILD = ln -sf vvp@EXEEXT@ vvp$(suffix)@EXEEXT@
VVP_CLEAN += vvp$(suffix)@EXEEXT@
endif
all: dep vvp@EXEEXT@ vvp.man
# ENV_VVP sets LD_LIBRARY_PATH by default to run vvp from the build tree
check: all
ifeq (@WIN32@,yes)
ifeq (@install_suffix@,)
./vvp -M../vpi $(srcdir)/examples/hello.vvp | grep 'Hello, World.'
else
# On Windows if we have a suffix we must run the vvp test with
# a suffix since it was built/linked that way.
ln vvp.exe vvp$(suffix).exe
./vvp$(suffix) -M../vpi $(srcdir)/examples/hello.vvp | grep 'Hello, World.'
rm -f vvp$(suffix).exe
endif
else
$(ENV_VVP) ./vvp -M../vpi $(srcdir)/examples/hello.vvp | grep 'Hello, World.'
endif
$(ENV_VVP) ./vvp$(suffix)@EXEEXT@ -M../vpi $(srcdir)/examples/hello.vvp | grep 'Hello, World.'
clean:
rm -f *.o *~ parse.cc parse.h lexor.cc tables.cc libvvp$(suffix).$(SLEXT)
rm -rf dep vvp@EXEEXT@ parse.output vvp.man vvp.ps vvp.pdf vvp.exp
rm -f *.o *~ parse.cc parse.h lexor.cc tables.cc $(LIB_CLEAN)
rm -f $(VVP_CLEAN) parse.output vvp.man vvp.ps vvp.pdf vvp.exp
rm -rf dep
distclean: clean
rm -f Makefile config.log
@ -136,30 +212,15 @@ dep:
mkdir dep
ifeq (@LIBVVP@,yes)
CPPFLAGS+= -fpic
# To avoid setting LD_LIBRARY_PATH when running vvp from the build tree,
# add option -Wl,-rpath=`pwd` to the CXX command below.
vvp@EXEEXT@: main.o $(srcdir)/vvp.def libvvp$(suffix).$(SLEXT)
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ main.o -L. $(LDFLAGS) -lvvp$(suffix) $(LIBS)
libvvp$(suffix).$(SLEXT): $LIB_OBJ
$(CXX) -shared $(LDFLAGS) -o libvvp$(suffix).$(SLEXT) $LIB_OBJ $(LIBS) $(dllib)
else
ifeq (@WIN32@,yes)
# To support cocotb, we export the VPI functions directly. This allows
# cocotb to build VPI modules without using our vpi_user.h and libvpi.a.
# The .def file controls what is exported.
vvp@EXEEXT@: main.o $LIB_OBJ $(srcdir)/vvp.def
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ $(LDFLAGS) $(srcdir)/vvp.def main.o $LIB_OBJ $(LIBS)
else
vvp@EXEEXT@: $LIB_OBJ main.o
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ main.o $LIB_OBJ $(LIBS)
endif
$(LIBBUILD): $(LIB_OBJ)
$(CXX) $(LDFLAGS_SHARED) $(LIBLINKFLAGS) -o $(LIBTARGET) $^ $(LIBS)
$(LIBPOSTBUILD)
endif
vvp@EXEEXT@: $(VVP_OBJ) $(VVP_DEPS)
$(CXX) $(LDFLAGS) -o $@ $(VVP_OBJ) -L. $(VVP_LDFLAGS) $(LIBS)
$(VVP_POSTBUILD)
%.o: %.cc config.h | dep
$(CXX) $(CPPFLAGS) -DIVL_SUFFIX='"$(suffix)"' $(MDIR1) $(MDIR2) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
mv $*.d dep/$*.d
@ -211,7 +272,7 @@ stamp-config-h: $(srcdir)/config.h.in ../config.status
cd ..; ./config.status --header=vvp/config.h
config.h: stamp-config-h
install: all installdirs installfiles
install: all installdirs installfiles installpkgconfig
F = ./vvp@EXEEXT@ $(srcdir)/libvvp.h $(INSTALL_DOC)
@ -224,24 +285,46 @@ installpdf: vvp.pdf installdirs
installfiles: $(F) | installdirs
$(INSTALL_PROGRAM) ./vvp@EXEEXT@ "$(DESTDIR)$(bindir)/vvp$(suffix)@EXEEXT@"
ifeq (@LIBVVP@,yes)
$(INSTALL_PROGRAM) ./libvvp$(suffix).$(SLEXT) "$(DESTDIR)$(SLDIR)/libvvp$(suffix).$(SLEXT)"
$(INSTALL_PROGRAM) ./$(LIBINSTALL) "$(DESTDIR)$(SLDIR)/$(LIBINSTALL)"
ifeq (@WIN32@,yes)
ifneq ($(LIBDEVELINSTALL),)
$(INSTALL_PROGRAM) ./$(LIBDEVELINSTALL) "$(DESTDIR)$(libdir)/$(LIBDEVELINSTALL)"
endif
else
# Install real library
ln -sf $(LIBREALNAME) "$(DESTDIR)$(SLDIR)/$(LIBSONAME)"
ln -sf $(LIBSONAME) "$(DESTDIR)$(SLDIR)/$(LIBLINKNAME)"
endif
$(INSTALL_DATA) $(srcdir)/libvvp.h "$(DESTDIR)$(ivl_includedir)/libvvp.h"
endif
installdirs: $(srcdir)/../mkinstalldirs
$(srcdir)/../mkinstalldirs "$(DESTDIR)$(bindir)" \
"$(DESTDIR)$(includedir)" \
"$(DESTDIR)$(ivl_includedir)" \
"$(DESTDIR)$(libdir)" \
"$(DESTDIR)$(docdir)" \
"$(DESTDIR)$(man1dir)"
installpkgconfig:
$(INSTALL) -d "$(DESTDIR)$(pkgconfigdir)"
$(INSTALL_DATA) libvvp.pc "$(DESTDIR)$(pkgconfigdir)/libvvp$(suffix).pc"
uninstall: $(UNINSTALL32)
rm -f "$(DESTDIR)$(bindir)/vvp$(suffix)@EXEEXT@"
rm -f "$(DESTDIR)$(man1dir)/vvp$(suffix).1" \
"$(DESTDIR)$(docdir)/vvp$(suffix).pdf"
ifeq (@LIBVVP@,yes)
rm -f "$(DESTDIR)$(SLDIR)/libvvp$(suffix).$(SLEXT)"
rm -f "$(DESTDIR)$(SLDIR)/$(LIBINSTALL)"
ifeq (@WIN32@,yes)
ifneq ($(LIBDEVELINSTALL),)
rm -f "$(DESTDIR)$(libdir)/$(LIBDEVELINSTALL)"
endif
else
rm -f "$(DESTDIR)$(SLDIR)/$(LIBLINKNAME)"
rm -f "$(DESTDIR)$(SLDIR)/$(LIBSONAME)"
rm -f "$(DESTDIR)$(SLDIR)/$(LIBREALNAME)"
endif
rm -f "$(DESTDIR)$(pkgconfigdir)/libvvp$(suffix).pc"
rm -f "$(DESTDIR)$(ivl_includedir)/libvvp.h"
endif

10
vvp/libvvp.pc.in Normal file
View File

@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libvvp@install_suffix@
Version: @VERSION_MAJOR@.@VERSION_MINOR@
Description: Icarus Verilog VVP runtime library
Libs: -L${libdir} -lvvp@install_suffix@
Cflags: -I${includedir}/iverilog@install_suffix@