Merge tag 'v2.3.10' into testing
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 16 Mar 2024 06:49:29 +0000 (07:49 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 16 Mar 2024 06:49:29 +0000 (07:49 +0100)
.settings/org.eclipse.core.resources.prefs [new file with mode: 0644]
.settings/org.eclipse.jdt.core.prefs
common.mk
jni.mk [new file with mode: 0644]
osgi.mk
repackage.mk
sdk/branches/testing.bnd
sdk/branches/unstable.bnd
src/org/argeo/build/Make.java
src/org/argeo/build/Repackage.java

diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644 (file)
index 0000000..99f26c0
--- /dev/null
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
index 997d6645bc7fc4b111db2c72d8fc646d5d9ebecc..ee4a9023875a90594bdaed6a66a9ea8947a931f3 100644 (file)
@@ -9,9 +9,18 @@ org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
 org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=17
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
 org.eclipse.jdt.core.compiler.problem.APILeak=warning
 org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
 org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
 org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
 org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
 org.eclipse.jdt.core.compiler.problem.deadCode=warning
@@ -20,6 +29,8 @@ org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
 org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
@@ -64,6 +75,7 @@ org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=igno
 org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
 org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
 org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
 org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
 org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
 org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
@@ -102,3 +114,5 @@ org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=17
index bc1bff95576d84bb30c74ea5b0009ac570348a7e..891f8f8d99347247cd9242a00138f1c060142298 100644 (file)
--- a/common.mk
+++ b/common.mk
@@ -6,8 +6,52 @@ ECJ_MAJOR=3
 BNDLIB_BRANCH=5.3
 SYSLOGGER_BRANCH=$(build-major).$(build-minor)
 
+# The following variables are found in the sdk.mk file which is generated by the configure script:
+# SDK_SRC_BASE      the base of the source code, typically the root of the cloned git repository
+# SDK_BUILD_BASE    the base of the output
+# JAVA_HOME         the base of the JDK used to build
+A2_OUTPUT = $(SDK_BUILD_BASE)/a2
+JVM ?= $(JAVA_HOME)/bin/java
+JAVADOC ?= $(JAVA_HOME)/bin/javadoc
+
 # GNU defaults
 prefix ?= /usr/local
 datarootdir ?= $(prefix)/share
+exec_prefix ?= $(prefix)
+libdir ?= $(exec_prefix)/lib
+
+A2_INSTALL_TARGET ?= $(DESTDIR)$(datarootdir)/a2
+A2_NATIVE_INSTALL_TARGET ?= $(DESTDIR)$(libdir)/a2
+
+# The following variables have default values which can be overriden
+# A2_BASE           the space-separated directories where already built a2 categories can be found
+A2_BASE ?=$(A2_OUTPUT) $(A2_INSTALL_TARGET) $(A2_NATIVE_INSTALL_TARGET) /usr/local/share/a2 /usr/local/lib/a2 /usr/share/a2 /usr/lib/a2
+
+# OS-speciific
+KNOWN_ARCHS ?= x86_64 aarch64
+TARGET_OS ?= linux
+TARGET_ARCH ?= $(shell uname -m)
+
+TARGET_OS_CATEGORY_PREFIX=lib/$(TARGET_OS)
+TARGET_ARCH_CATEGORY_PREFIX=$(TARGET_OS_CATEGORY_PREFIX)/$(TARGET_ARCH)
+PORTABLE_CATEGORIES=$(filter-out lib/%, $(CATEGORIES))
+ARCH_CATEGORIES=$(filter $(TARGET_ARCH_CATEGORY_PREFIX)/%, $(CATEGORIES))
+OS_CATEGORIES=$(filter-out $(foreach arch, $(KNOWN_ARCHS), $(TARGET_OS_CATEGORY_PREFIX)/$(arch)/%), $(filter $(TARGET_OS_CATEGORY_PREFIX)/%, $(CATEGORIES)))
+
+## Utilities
+# Install to a target directory without executable bit
+INSTALL=install -m644 -D --target-directory
+# Always try copy-on-write
+COPY=--reflink=auto
+# Recursively delete directories
+RMDIR=$(RM) -r
+
+# Make variables used to replace spaces by a separator, typically in order to generate classpaths
+# for example: CLASSPATH = $(subst $(space),$(pathsep),$(strip $(JARS)))
+null  :=
+space := $(null) #
+pathsep := :
+define LF
 
-A2_INSTALL_TARGET ?= $(DESTDIR)$(datarootdir)/a2
\ No newline at end of file
+$(null)
+endef
diff --git a/jni.mk b/jni.mk
new file mode 100644 (file)
index 0000000..1892613
--- /dev/null
+++ b/jni.mk
@@ -0,0 +1,74 @@
+ARGEO_BUILD_BASE := $(dir $(lastword $(MAKEFILE_LIST)))
+include $(ARGEO_BUILD_BASE)common.mk
+
+# The following variables should be declared in the including Makefile:
+# NATIVE_PACKAGE    this native package name
+# A2_CATEGORY       the (single) a2 category the bundles will belong to
+
+# The following variables have default values which can be overriden
+# DEP_NATIVE        space-separated logical names of named depdencies
+# DEP_INCLUDES      additional includes
+# DEP_LIBS          additional native libraries
+DEP_NATIVE ?=
+DEP_INCLUDES ?= $(foreach dep, $(DEP_NATIVE), /usr/include/$(dep))
+DEP_LIBS ?= $(foreach dep, $(DEP_NATIVE), -l$(dep))
+
+A2_NATIVE_CATEGORY=$(A2_OUTPUT)/lib/linux/$(shell uname -m)/$(A2_CATEGORY)
+TARGET_EXEC := libJava_$(NATIVE_PACKAGE).$(major).$(minor).so
+
+LDFLAGS ?= -shared -fPIC -Wl,-soname,$(TARGET_EXEC).$(major).$(minor).$(micro) $(DEP_LIBS)
+CFLAGS ?= -O3 -fPIC
+
+SRC_DIRS := . 
+
+#
+# Generic Argeo
+#
+BUILD_DIR := $(SDK_BUILD_BASE)/jni/$(NATIVE_PACKAGE)
+
+# Include directories
+INC_DIRS := $(shell find $(SRC_DIRS) -type d) $(JAVA_HOME)/include $(JAVA_HOME)/include/linux $(DEP_INCLUDES)
+
+all: $(A2_NATIVE_CATEGORY)/$(TARGET_EXEC)
+
+clean:
+       $(RM) $(BUILD_DIR)/*.o
+       $(RM) $(A2_NATIVE_CATEGORY)/$(TARGET_EXEC)
+
+install:
+       $(INSTALL) $(A2_NATIVE_INSTALL_TARGET)/$(A2_CATEGORY) $(A2_NATIVE_CATEGORY)/$(TARGET_EXEC)
+
+uninstall:
+       $(RM) $(A2_NATIVE_INSTALL_TARGET)/$(A2_CATEGORY)/$(TARGET_EXEC)
+       @if [ -d $(A2_NATIVE_INSTALL_TARGET) ]; then find $(A2_NATIVE_INSTALL_TARGET) -empty -type d -delete; fi
+
+# Sources
+SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')
+# Objects (example.cpp to ./org_example_core/example.cpp.o)
+OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
+# Dependencies (example.cpp.o to ./org_example_core/example.cpp.d)
+DEPS := $(OBJS:.o=.d)
+# Add -I prefix to include directories
+INC_FLAGS := $(addprefix -I,$(INC_DIRS))
+# Generate dependencies makefiles
+CPPFLAGS := $(INC_FLAGS) -MMD -MP
+
+# Final build step
+$(A2_NATIVE_CATEGORY)/$(TARGET_EXEC): $(OBJS)
+       mkdir -p $(A2_NATIVE_CATEGORY)
+       $(CC) $(OBJS) -o $@ $(LDFLAGS)
+
+# Build step for C source
+$(BUILD_DIR)/%.c.o: %.c
+       mkdir -p $(dir $@)
+       $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+# Build step for C++ source
+$(BUILD_DIR)/%.cpp.o: %.cpp
+       mkdir -p $(dir $@)
+       $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
+
+# Include the .d makefiles. (- pefix suppress errors if not found)
+-include $(DEPS)
+
+.PHONY: clean all install uninstall
diff --git a/osgi.mk b/osgi.mk
index ca17cbe820b8fb7b7f7150da2f3d7f4085cab2e3..334714bf6ad9f6d37ac2c39edfda1ede82e5389e 100644 (file)
--- a/osgi.mk
+++ b/osgi.mk
@@ -1,37 +1,27 @@
 ARGEO_BUILD_BASE := $(dir $(lastword $(MAKEFILE_LIST)))
 include $(ARGEO_BUILD_BASE)common.mk
-#
-# Common build routines to be included in Makefiles
-#
-# The following variables are found in the sdk.mk file which is generated by the configure script:
-# SDK_SRC_BASE         the base of the source code, typically the root of the cloned git repository
-# SDK_BUILD_BASE       the base of the output
-# JAVA_HOME                    the base of the JDK used to build
-A2_OUTPUT = $(SDK_BUILD_BASE)/a2
-JVM ?= $(JAVA_HOME)/bin/java
-JAVADOC ?= $(JAVA_HOME)/bin/javadoc
 
 # The following variables should be declared in the including Makefile:
-# BUNDLES                      the space-separated list of bundles to build
-# A2_CATEGORY          the (single) a2 category the bundles will belong to
+# BUNDLES           the space-separated list of bundles to build
+# A2_CATEGORY       the (single) a2 category the bundles will belong to
 
 # The following environment variables can change the behaviour of the build
-# SOURCE_BUNDLES       sources will be packaged separately in Eclipse-compatible source bundles
-# NO_MANIFEST_COPY     generated MANIFESTs won't be copied to the source tree
+# SOURCE_BUNDLES    sources will be packaged separately in Eclipse-compatible source bundles
+# NO_MANIFEST_COPY  generated MANIFESTs won't be copied to the source tree
 
 # The following variables have default values which can be overriden
-# DEP_CATEGORIES       the a2 categories the compilation depends on
-# JAVADOC_PACKAGES     the space-separated list of packages for which javadoc will be generated
-# A2_BASE                      the space-separated directories where already built a2 categories can be found
+# DEP_CATEGORIES    the a2 categories the compilation depends on
+# JAVADOC_PACKAGES  the space-separated list of packages for which javadoc will be generated
+# NATIVE_PACKAGES   the space-separated list of JNI packages (directories)
 DEP_CATEGORIES ?=
 JAVADOC_PACKAGES ?=
-A2_BASE ?=/usr/share/a2 /usr/local/share/a2 $(A2_OUTPUT)
+NATIVE_PACKAGES ?=
 
 # We always use the latest version of the ECJ compiler
-ECJ_JAR ?= $(lastword $(foreach base, $(A2_BASE), $(sort $(wildcard $(base)/org.argeo.tp.build/org.eclipse.jdt.core.compiler.batch.$(ECJ_MAJOR).*.jar))))
+ECJ_JAR ?= $(firstword $(foreach base, $(A2_BASE), $(sort $(wildcard $(base)/org.argeo.tp.build/org.eclipse.jdt.core.compiler.batch.$(ECJ_MAJOR).*.jar))))
 # Third-party libraries
-LOGGER_JAR ?= $(lastword $(foreach base, $(A2_BASE), $(wildcard $(base)/log/syslogger/org.argeo.tp/org.argeo.tp.syslogger.$(SYSLOGGER_BRANCH).jar)))
-BNDLIB_JAR ?= $(lastword $(foreach base, $(A2_BASE), $(wildcard $(base)/org.argeo.tp.build/biz.aQute.bndlib.$(BNDLIB_BRANCH).jar)))
+LOGGER_JAR ?= $(firstword $(foreach base, $(A2_BASE), $(wildcard $(base)/log/syslogger/org.argeo.tp/org.argeo.tp.syslogger.$(SYSLOGGER_BRANCH).jar)))
+BNDLIB_JAR ?= $(firstword $(foreach base, $(A2_BASE), $(wildcard $(base)/org.argeo.tp.build/biz.aQute.bndlib.$(BNDLIB_BRANCH).jar)))
 
 # Internal variables
 ARGEO_MAKE = $(JVM) -cp $(LOGGER_JAR):$(ECJ_JAR):$(BNDLIB_JAR) $(ARGEO_BUILD_BASE)src/org/argeo/build/Make.java
@@ -42,10 +32,11 @@ endif
 BUILD_BASE = $(SDK_BUILD_BASE)/$(shell basename $(SDK_SRC_BASE))
 TARGET_BUNDLES =  $(abspath $(foreach bundle, $(BUNDLES),$(A2_OUTPUT)/$(shell dirname $(bundle))/$(A2_CATEGORY)/$(shell basename $(bundle)).$(major).$(minor).jar))
 TODOS = $(foreach bundle, $(BUNDLES),$(BUILD_BASE)/$(bundle)/to-build) 
+# Native
+JNIDIRS=$(foreach package, $(NATIVE_PACKAGES), jni/$(package))
 
 # Needed in order to be able to expand $$ variables
 .SECONDEXPANSION:
-.PHONY: osgi manifests javadoc
 
 osgi: $(BUILD_BASE)/built $(MANIFESTS)
 
@@ -81,22 +72,37 @@ endif
 clean-manifests :
        @rm -rf $(foreach bundle, $(BUNDLES), $(bundle)/META-INF/MANIFEST.MF);
 
-osgi-install:
+osgi-all: osgi jni-all
+
+osgi-clean: jni-clean
+       rm -rf $(BUILD_BASE)
+
+osgi-install: jni-install
        $(ARGEO_MAKE) \
         install --category $(A2_CATEGORY) --bundles $(BUNDLES) \
-        --target $(A2_INSTALL_TARGET)
+        --target $(A2_INSTALL_TARGET) \
+        --os $(TARGET_OS) --target-native $(A2_NATIVE_INSTALL_TARGET)
 
-osgi-uninstall:
+osgi-uninstall: jni-uninstall
        $(ARGEO_MAKE) \
         uninstall --category $(A2_CATEGORY) --bundles $(BUNDLES) \
-        --target $(A2_INSTALL_TARGET)
+        --target $(A2_INSTALL_TARGET) \
+        --os $(TARGET_OS) --target-native $(A2_NATIVE_INSTALL_TARGET)
+
+jni-all: 
+       $(foreach dir, $(JNIDIRS), $(MAKE) -C $(dir) all;)
+       
+jni-clean:
+       $(foreach dir, $(JNIDIRS), $(MAKE) -C $(dir) clean;)
+
+jni-install:
+       $(foreach dir, $(JNIDIRS), $(MAKE) -C $(dir) install;)
+
+jni-uninstall:
+       $(foreach dir, $(JNIDIRS), $(MAKE) -C $(dir) uninstall;)
 
 # Javadoc generation
 javadoc: $(BUILD_BASE)/built
        $(JAVADOC) -noindex -quiet -Xmaxwarns 1 -d $(BUILD_BASE)/api --source-path $(subst $(space),$(pathsep),$(strip $(JAVADOC_SRCS))) -subpackages $(JAVADOC_PACKAGES)
 
-# Make variables used to replace spaces by a separator, typically in order to generate classpaths
-# for example: CLASSPATH = $(subst $(space),$(pathsep),$(strip $(JARS)))
-null  :=
-space := $(null) #
-pathsep := :
\ No newline at end of file
+.PHONY: osgi manifests javadoc osgi-all osgi-clean osgi-install osgi-uninstall jni-all jni-clean jni-install jni-uninstall
index 5a14bb727bac006f3e887aaf24f6b74d0636e7a5..87ce9072bdbf916cf3b4987067ec6993899d7a32 100644 (file)
@@ -1,25 +1,14 @@
 ARGEO_BUILD_BASE := $(dir $(lastword $(MAKEFILE_LIST)))
 include $(ARGEO_BUILD_BASE)common.mk
-#
-# Common repackage routines to be included in Makefiles
-#
-# The following variables are found in the sdk.mk file which is generated by the configure script:
-# SDK_SRC_BASE         the base of the source code, typically the root of the cloned git repository
-# SDK_BUILD_BASE       the base of the output
-# JAVA_HOME                    the base of the JDK used to build
-A2_OUTPUT = $(SDK_BUILD_BASE)/a2
-JVM ?= $(JAVA_HOME)/bin/java
 
 # The following variables should be declared in the including Makefile:
-# CATEGORIES           the space-separated list of categories to repackage
+# CATEGORIES        the space-separated list of categories to repackage
 
-# The following variables have default values which can be overriden
-# A2_BASE                      the space-separated directories where already built a2 categories can be found
 A2_BASE ?=/usr/share/a2 /usr/local/share/a2 $(A2_OUTPUT)
 
 # Third-party libraries
-LOGGER_JAR ?= $(lastword $(foreach base, $(A2_BASE), $(wildcard $(base)/log/syslogger/org.argeo.tp/org.argeo.tp.syslogger.$(SYSLOGGER_BRANCH).jar)))
-BNDLIB_JAR ?= $(lastword $(foreach base, $(A2_BASE), $(wildcard $(base)/org.argeo.tp.build/biz.aQute.bndlib.$(BNDLIB_BRANCH).jar)))
+LOGGER_JAR ?= $(firstword $(foreach base, $(A2_BASE), $(wildcard $(base)/log/syslogger/org.argeo.tp/org.argeo.tp.syslogger.$(SYSLOGGER_BRANCH).jar)))
+BNDLIB_JAR ?= $(firstword $(foreach base, $(A2_BASE), $(wildcard $(base)/org.argeo.tp.build/biz.aQute.bndlib.$(BNDLIB_BRANCH).jar)))
 
 # Internal variables
 ARGEO_REPACKAGE = $(JVM) -cp $(LOGGER_JAR):$(BNDLIB_JAR) $(ARGEO_BUILD_BASE)src/org/argeo/build/Repackage.java
@@ -30,13 +19,28 @@ REPACKAGED_CATEGORIES = $(foreach category, $(CATEGORIES),$(A2_OUTPUT)/$(categor
 all: $(BUILD_BASE)/repackaged 
 
 install:
-       @$(foreach category, $(CATEGORIES), mkdir -p $(A2_INSTALL_TARGET)/$(category);  cp $(A2_OUTPUT)/$(category)/*.jar $(A2_INSTALL_TARGET)/$(category);)
-       @echo Installed $(CATEGORIES) to $(A2_INSTALL_TARGET)
+       @$(foreach category, $(PORTABLE_CATEGORIES), $(INSTALL) $(A2_INSTALL_TARGET)/$(category) $(wildcard $(A2_OUTPUT)/$(category)/*.jar);$(LF))
+       @echo Installed portable jars \'$(PORTABLE_CATEGORIES)\' to $(A2_INSTALL_TARGET)
+       @$(foreach category, $(OS_CATEGORIES), $(INSTALL) $(A2_INSTALL_TARGET)/$(category:$(TARGET_OS_CATEGORY_PREFIX)/%=%) $(wildcard $(A2_OUTPUT)/$(category)/*.jar);$(LF))
+       @echo Installed OS-dependent jars \'$(OS_CATEGORIES)\' to $(A2_INSTALL_TARGET)
+       @$(foreach category, $(ARCH_CATEGORIES), $(INSTALL) $(A2_NATIVE_INSTALL_TARGET)/$(category:$(TARGET_ARCH_CATEGORY_PREFIX)/%=%) $(wildcard $(A2_OUTPUT)/$(category)/*.jar);$(LF))
+       @echo Installed arch-dependent jars \'$(ARCH_CATEGORIES)\' to $(A2_NATIVE_INSTALL_TARGET)
+       @$(foreach category, $(ARCH_CATEGORIES), $(INSTALL) $(A2_NATIVE_INSTALL_TARGET)/$(category:$(TARGET_ARCH_CATEGORY_PREFIX)/%=%) $(wildcard $(A2_OUTPUT)/$(category)/*.so);$(LF))
+       @echo Installed arch binaries \'$(ARCH_CATEGORIES)\' to $(A2_NATIVE_INSTALL_TARGET)
 
 uninstall:
-       @$(foreach category, $(CATEGORIES), rm -rf $(A2_INSTALL_TARGET)/$(category);)
-       @find $(A2_INSTALL_TARGET) -empty -type d -delete
-       @echo Uninstalled $(CATEGORIES) from $(A2_INSTALL_TARGET)
+       @$(foreach category, $(PORTABLE_CATEGORIES), $(RMDIR) $(A2_INSTALL_TARGET)/$(category);$(LF))
+       @echo Uninstalled portable jars \'$(PORTABLE_CATEGORIES)\' to $(A2_INSTALL_TARGET)
+       @$(foreach category, $(OS_CATEGORIES), $(RMDIR) $(A2_INSTALL_TARGET)/$(category:$(TARGET_OS_CATEGORY_PREFIX)/%=%);$(LF))
+       @echo Uninstalled OS-dependent jars \'$(OS_CATEGORIES)\' to $(A2_INSTALL_TARGET)
+       @$(foreach category, $(ARCH_CATEGORIES), $(RMDIR) $(A2_NATIVE_INSTALL_TARGET)/$(category:$(TARGET_ARCH_CATEGORY_PREFIX)/%=%);$(LF))
+       @echo Uninstalled arch-dependent jars and binaries \'$(ARCH_CATEGORIES)\' to $(A2_NATIVE_INSTALL_TARGET)
+#      @$(foreach category, $(ARCH_CATEGORIES), \
+#       $(foreach libfile, $(wildcard $(A2_OUTPUT)/$(category)/*.so), $(RMDIR) $(A2_NATIVE_INSTALL_TARGET)/$(notdir $(libfile));$(LF)) \
+#      )
+#      @echo Uninstalled arch binaries \'$(ARCH_CATEGORIES)\' to $(A2_NATIVE_INSTALL_TARGET)
+       @if [ -d $(A2_INSTALL_TARGET) ]; then find $(A2_INSTALL_TARGET) -empty -type d -delete; fi
+       @if [ -d $(A2_NATIVE_INSTALL_TARGET) ]; then find $(A2_NATIVE_INSTALL_TARGET) -empty -type d -delete; fi
 
 .SECONDEXPANSION:
 # We use .SECONDEXPANSION and CATEGORIES_TO_REPACKAGE instead of directly CATEGORIES
index a8ddda368c222c82117838968cc5a11d8d73a131..e8a57b2e003a3fa3665a4a9107e9921f79fd90f6 100644 (file)
@@ -1,6 +1,6 @@
 major=2
 minor=1
 micro=5
-qualifier=
+qualifier=.next
 
 SPDX-License-Identifier=CC0-1.0
\ No newline at end of file
index 9ba0e10e6d41b7881406eb9bffc8cde7f2e97428..6f4133498242bf2bb176b130073a02e00295555e 100644 (file)
@@ -1,6 +1,6 @@
 major=2
 minor=3
-micro=9
+micro=10
 qualifier=
 
 SPDX-License-Identifier=CC0-1.0
\ No newline at end of file
index 34477cf7639ebcc22ec2800c81a7aaa86479c830..b0066ac99bdf7ca0295b1bef5aef8e04efe4e882 100644 (file)
@@ -38,6 +38,7 @@ import java.util.jar.Attributes;
 import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
 import java.util.jar.Manifest;
+import java.util.stream.Collectors;
 import java.util.zip.Deflater;
 
 import org.eclipse.jdt.core.compiler.CompilationProgress;
@@ -175,7 +176,8 @@ public class Make {
 
                List<String> a2Categories = options.getOrDefault("--dep-categories", new ArrayList<>());
                List<String> a2Bases = options.getOrDefault("--a2-bases", new ArrayList<>());
-               if (a2Bases.isEmpty() || !a2Bases.contains(a2Output.toString())) {
+               a2Bases = a2Bases.stream().distinct().collect(Collectors.toList());// remove duplicates
+               if (a2Bases.isEmpty() || !a2Bases.contains(a2Output.toString())) {// make sure a2 output is available
                        a2Bases.add(a2Output.toString());
                }
 
@@ -204,10 +206,9 @@ public class Make {
                                                        A2Jar current = a2Jars.get(a2Jar.name);
                                                        if (a2Jar.major > current.major)
                                                                a2Jars.put(a2Jar.name, a2Jar);
-                                                       else if (a2Jar.major == current.major //
-                                                                       // if minor equals, we take the last one
-                                                                       && a2Jar.minor >= current.minor)
+                                                       else if (a2Jar.major == current.major && a2Jar.minor > current.minor)
                                                                a2Jars.put(a2Jar.name, a2Jar);
+                                                       // keep if minor equals
                                                } else {
                                                        a2Jars.put(a2Jar.name, a2Jar);
                                                }
@@ -312,26 +313,21 @@ public class Make {
                logger.log(DEBUG, "Packaging took " + duration + " ms");
        }
 
-       /** Install the bundles. */
+       /** Install or uninstall bundles and native output. */
        void install(Map<String, List<String>> options, boolean uninstall) throws IOException {
+               final String LIB_ = "lib/";
+               final String NATIVE_ = "native/";
+
                // check arguments
-               List<String> bundles = options.get("--bundles");
-               Objects.requireNonNull(bundles, "--bundles argument must be set");
+               List<String> bundles = multiArg(options, "--bundles", true);
                if (bundles.isEmpty())
                        return;
-
-               List<String> categories = options.get("--category");
-               Objects.requireNonNull(categories, "--category argument must be set");
-               if (categories.size() != 1)
-                       throw new IllegalArgumentException("One and only one --category must be specified");
-               String category = categories.get(0);
-
-               List<String> targetDirs = options.get("--target");
-               Objects.requireNonNull(targetDirs, "--target argument must be set");
-               if (targetDirs.size() != 1)
-                       throw new IllegalArgumentException("One and only one --target must be specified");
-               Path targetA2 = Paths.get(targetDirs.get(0));
-               logger.log(INFO, (uninstall ? "Uninstalling from " : "Installing to ") + targetA2);
+               String category = singleArg(options, "--category", true);
+               Path targetA2 = Paths.get(singleArg(options, "--target", true));
+               String nativeTargetArg = singleArg(options, "--target-native", false);
+               Path nativeTargetA2 = nativeTargetArg != null ? Paths.get(nativeTargetArg) : null;
+               String targetOs = singleArg(options, "--os", nativeTargetArg != null);
+               logger.log(INFO, (uninstall ? "Uninstalling bundles from " : "Installing bundles to ") + targetA2);
 
                final String branch;
                Path branchMk = sdkSrcBase.resolve(BRANCH_MK);
@@ -354,14 +350,28 @@ public class Make {
                Objects.requireNonNull(minor, "'minor' must be set");
 
                int count = 0;
-               for (String bundle : bundles) {
+               bundles: for (String bundle : bundles) {
                        Path bundlePath = Paths.get(bundle);
                        Path bundleParent = bundlePath.getParent();
                        Path a2JarDirectory = bundleParent != null ? a2Output.resolve(bundleParent).resolve(category)
                                        : a2Output.resolve(category);
                        Path jarP = a2JarDirectory.resolve(bundlePath.getFileName() + "." + major + "." + minor + ".jar");
 
-                       Path targetJarP = targetA2.resolve(a2Output.relativize(jarP));
+                       Path targetJarP;
+                       if (bundle.startsWith(LIB_)) {// OS-specific
+                               Objects.requireNonNull(nativeTargetA2);
+                               if (bundle.startsWith(LIB_ + NATIVE_) // portable native
+                                               || bundle.startsWith(LIB_ + targetOs + "/" + NATIVE_)) {// OS-specific native
+                                       targetJarP = nativeTargetA2.resolve(category).resolve(jarP.getFileName());
+                               } else if (bundle.startsWith(LIB_ + targetOs)) {// OS-specific portable
+                                       targetJarP = targetA2.resolve(category).resolve(jarP.getFileName());
+                               } else { // ignore other OS
+                                       continue bundles;
+                               }
+                       } else {
+                               targetJarP = targetA2.resolve(a2Output.relativize(jarP));
+                       }
+
                        if (uninstall) { // uninstall
                                if (Files.exists(targetJarP)) {
                                        Files.delete(targetJarP);
@@ -369,7 +379,10 @@ public class Make {
                                        count++;
                                }
                                Path targetParent = targetJarP.getParent();
-                               deleteEmptyParents(targetA2, targetParent);
+                               if (targetParent.startsWith(targetA2))
+                                       deleteEmptyParents(targetA2, targetParent);
+                               if (nativeTargetA2 != null && targetParent.startsWith(nativeTargetA2))
+                                       deleteEmptyParents(nativeTargetA2, targetParent);
                        } else { // install
                                Files.createDirectories(targetJarP.getParent());
                                boolean update = Files.exists(targetJarP);
@@ -381,16 +394,45 @@ public class Make {
                logger.log(INFO, uninstall ? count + " bundles removed" : count + " bundles installed or updated");
        }
 
-       /** Delete empty parent directory up to the A2 target (included). */
-       void deleteEmptyParents(Path targetA2, Path targetParent) throws IOException {
+       /** Extracts an argument which must be unique. */
+       String singleArg(Map<String, List<String>> options, String arg, boolean mandatory) {
+               List<String> values = options.get(arg);
+               if (values == null || values.size() == 0)
+                       if (mandatory)
+                               throw new IllegalArgumentException(arg + " argument must be set");
+                       else
+                               return null;
+               if (values.size() != 1)
+                       throw new IllegalArgumentException("One and only one " + arg + " arguments must be specified");
+               return values.get(0);
+       }
+
+       /** Extracts an argument which can have multiple values. */
+       List<String> multiArg(Map<String, List<String>> options, String arg, boolean mandatory) {
+               List<String> values = options.get(arg);
+               if (mandatory && values == null)
+                       throw new IllegalArgumentException(arg + " argument must be set");
+               return values != null ? values : new ArrayList<>();
+       }
+
+       /** Delete empty parent directory up to the base directory (included). */
+       void deleteEmptyParents(Path baseDir, Path targetParent) throws IOException {
+               if (!targetParent.startsWith(baseDir))
+                       throw new IllegalArgumentException(targetParent + " does not start with " + baseDir);
+               if (!Files.exists(baseDir))
+                       return;
+               if (!Files.exists(targetParent)) {
+                       deleteEmptyParents(baseDir, targetParent.getParent());
+                       return;
+               }
                if (!Files.isDirectory(targetParent))
                        throw new IllegalArgumentException(targetParent + " must be a directory");
-               boolean isA2target = Files.isSameFile(targetA2, targetParent);
+               boolean isA2target = Files.isSameFile(baseDir, targetParent);
                if (!Files.list(targetParent).iterator().hasNext()) {
                        Files.delete(targetParent);
                        if (isA2target)
                                return;// stop after deleting A2 base
-                       deleteEmptyParents(targetA2, targetParent.getParent());
+                       deleteEmptyParents(baseDir, targetParent.getParent());
                }
        }
 
index 5b5247bcd999a4a25b44e57568b67eb73f3dd162..2a9331d559e611c943c53f2192a52741ecb4a270 100644 (file)
@@ -23,6 +23,7 @@ import static org.argeo.build.Repackage.ManifestHeader.BUNDLE_VERSION;
 import static org.argeo.build.Repackage.ManifestHeader.ECLIPSE_SOURCE_BUNDLE;
 import static org.argeo.build.Repackage.ManifestHeader.EXPORT_PACKAGE;
 import static org.argeo.build.Repackage.ManifestHeader.IMPORT_PACKAGE;
+import static org.argeo.build.Repackage.ManifestHeader.REQUIRE_BUNDLE;
 import static org.argeo.build.Repackage.ManifestHeader.SPDX_LICENSE_IDENTIFIER;
 
 import java.io.BufferedWriter;
@@ -32,8 +33,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.System.Logger;
-import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.DirectoryStream;
 import java.nio.file.FileSystem;
@@ -148,6 +149,8 @@ public class Repackage {
                EXPORT_PACKAGE("Export-Package"), //
                /** OSGi imported packages list. */
                IMPORT_PACKAGE("Import-Package"), //
+               /** OSGi required bundles. */
+               REQUIRE_BUNDLE("Require-Bundle"), //
                /** OSGi path to embedded jar. */
                BUNDLE_CLASSPATH("Bundle-Classpath"), //
                // Java
@@ -174,7 +177,7 @@ public class Repackage {
                /** Maven repository, if not the default one. */
                ARGEO_ORIGIN_M2_REPO("Argeo-Origin-M2-Repo"), //
                /**
-                * Do not perform BND analysis of the origin component. Typically Import_package
+                * Do not perform BND analysis of the origin component. Typically Import-Package
                 * and Export-Package will be kept untouched.
                 */
                ARGEO_ORIGIN_NO_METADATA_GENERATION("Argeo-Origin-NoMetadataGeneration"), //
@@ -773,7 +776,7 @@ public class Repackage {
                                        : null;
                        String alternateUri = props.getProperty(ARGEO_ORIGIN_SOURCES_URI.toString());
                        M2Artifact sourcesArtifact = new M2Artifact(artifact.toM2Coordinates(), "sources");
-                       URL sourcesUrl = alternateUri != null ? new URL(alternateUri)
+                       URI sourcesUrl = alternateUri != null ? new URI(alternateUri)
                                        : M2ConventionsUtils.mavenRepoUrl(repoStr, sourcesArtifact);
                        Path sourcesDownloaded = downloadMaven(sourcesUrl, sourcesArtifact);
                        processM2SourceJar(sourcesDownloaded, targetBundleDir, merging ? artifact : null, unmodified);
@@ -847,13 +850,17 @@ public class Repackage {
                                ? props.getProperty(ARGEO_ORIGIN_M2_REPO.toString())
                                : null;
                String alternateUri = props.getProperty(ARGEO_ORIGIN_URI.toString());
-               URL url = alternateUri != null ? new URL(alternateUri) : M2ConventionsUtils.mavenRepoUrl(repoStr, artifact);
-               return downloadMaven(url, artifact);
+               try {
+                       URI uri = alternateUri != null ? new URI(alternateUri) : M2ConventionsUtils.mavenRepoUrl(repoStr, artifact);
+                       return downloadMaven(uri, artifact);
+               } catch (URISyntaxException e) {
+                       throw new IllegalArgumentException("Wrong aritfact URI", e);
+               }
        }
 
        /** Download a Maven artifact. */
-       Path downloadMaven(URL url, M2Artifact artifact) throws IOException {
-               return download(url, mavenBase, M2ConventionsUtils.artifactPath("", artifact));
+       Path downloadMaven(URI uri, M2Artifact artifact) throws IOException {
+               return download(uri, mavenBase, M2ConventionsUtils.artifactPath("", artifact));
        }
 
        /*
@@ -1122,8 +1129,9 @@ public class Repackage {
                                Files.copy(jarIn, target);
 
                                // native libraries
+                               boolean removeDllFromJar = true;
                                if (isNative && (entry.getName().endsWith(".so") || entry.getName().endsWith(".dll")
-                                               || entry.getName().endsWith(".jnilib"))) {
+                                               || entry.getName().endsWith(".jnilib") || entry.getName().endsWith(".a"))) {
                                        Path categoryDir = bundleDir.getParent();
                                        boolean copyDll = false;
                                        Path targetDll = categoryDir.resolve(bundleDir.relativize(target));
@@ -1145,8 +1153,11 @@ public class Repackage {
                                                        Files.delete(targetDll);
                                                Files.copy(target, targetDll);
                                        }
-                                       Files.delete(target);
-                                       origin.deleted.add(bundleDir.relativize(target).toString());
+
+                                       if (removeDllFromJar) {
+                                               Files.delete(target);
+                                               origin.deleted.add(bundleDir.relativize(target).toString());
+                                       }
                                }
                                logger.log(TRACE, () -> "Copied " + target);
                        }
@@ -1208,7 +1219,11 @@ public class Repackage {
                for (Iterator<Map.Entry<Object, Object>> manifestEntries = manifest.getMainAttributes().entrySet()
                                .iterator(); manifestEntries.hasNext();) {
                        Map.Entry<Object, Object> manifestEntry = manifestEntries.next();
-                       switch (manifestEntry.getKey().toString()) {
+                       String key = manifestEntry.getKey().toString();
+                       // TODO make it more generic
+                       if (key.equals(REQUIRE_BUNDLE.toString()) && nameVersion.getName().equals("com.sun.jna.platform"))
+                               manifestEntries.remove();
+                       switch (key) {
                        case "Archiver-Version":
                        case "Build-By":
                        case "Created-By":
@@ -1309,12 +1324,12 @@ public class Repackage {
        }
 
        /** Try to download from an URI. */
-       Path tryDownloadArchive(String uri, Path dir) throws IOException {
+       Path tryDownloadArchive(String uriStr, Path dir) throws IOException {
                // find mirror
                List<String> urlBases = null;
                String uriPrefix = null;
                uriPrefixes: for (String uriPref : mirrors.keySet()) {
-                       if (uri.startsWith(uriPref)) {
+                       if (uriStr.startsWith(uriPref)) {
                                if (mirrors.get(uriPref).size() > 0) {
                                        urlBases = mirrors.get(uriPref);
                                        uriPrefix = uriPref;
@@ -1324,56 +1339,56 @@ public class Repackage {
                }
                if (urlBases == null)
                        try {
-                               return downloadArchive(new URL(uri), dir);
-                       } catch (FileNotFoundException e) {
-                               throw new FileNotFoundException("Cannot find " + uri);
+                               return downloadArchive(new URI(uriStr), dir);
+                       } catch (FileNotFoundException | URISyntaxException e) {
+                               throw new FileNotFoundException("Cannot find " + uriStr);
                        }
 
                // try to download
                for (String urlBase : urlBases) {
-                       String relativePath = uri.substring(uriPrefix.length());
-                       URL url = new URL(urlBase + relativePath);
+                       String relativePath = uriStr.substring(uriPrefix.length());
+                       String uStr = urlBase + relativePath;
                        try {
-                               return downloadArchive(url, dir);
-                       } catch (FileNotFoundException e) {
-                               logger.log(WARNING, "Cannot download " + url + ", trying another mirror");
+                               return downloadArchive(new URI(uStr), dir);
+                       } catch (FileNotFoundException | URISyntaxException e) {
+                               logger.log(WARNING, "Cannot download " + uStr + ", trying another mirror");
                        }
                }
-               throw new FileNotFoundException("Cannot find " + uri);
+               throw new FileNotFoundException("Cannot find " + uriStr);
        }
 
        /**
         * Effectively download an archive.
         */
-       Path downloadArchive(URL url, Path dir) throws IOException {
-               return download(url, dir, (String) null);
+       Path downloadArchive(URI uri, Path dir) throws IOException {
+               return download(uri, dir, (String) null);
        }
 
        /**
         * Effectively download. Synchronised in order to avoid downloading twice in
         * parallel.
         */
-       synchronized Path download(URL url, Path dir, String name) throws IOException {
+       synchronized Path download(URI uri, Path dir, String name) throws IOException {
 
                Path dest;
                if (name == null) {
                        // We use also use parent directory in case the archive itself has a fixed name
-                       String[] segments = url.getPath().split("/");
+                       String[] segments = uri.getPath().split("/");
                        name = segments.length > 1 ? segments[segments.length - 2] + '-' + segments[segments.length - 1]
                                        : segments[segments.length - 1];
                }
 
                dest = dir.resolve(name);
                if (Files.exists(dest)) {
-                       logger.log(TRACE, () -> "File " + dest + " already exists for " + url + ", not downloading again");
+                       logger.log(TRACE, () -> "File " + dest + " already exists for " + uri + ", not downloading again");
                        return dest;
                } else {
                        Files.createDirectories(dest.getParent());
                }
 
-               try (InputStream in = url.openStream()) {
+               try (InputStream in = uri.toURL().openStream()) {
                        Files.copy(in, dest);
-                       logger.log(DEBUG, () -> "Downloaded " + dest + " from " + url);
+                       logger.log(DEBUG, () -> "Downloaded " + dest + " from " + uri);
                }
                return dest;
        }
@@ -1633,14 +1648,9 @@ class M2ConventionsUtils {
        }
 
        /** Absolute path to the file */
-       static URL mavenRepoUrl(String repoBase, M2Artifact artifact) {
-               String url = artifactUrl(repoBase == null ? MAVEN_CENTRAL_BASE_URL : repoBase, artifact);
-               try {
-                       return new URL(url);
-               } catch (MalformedURLException e) {
-                       // it should not happen
-                       throw new IllegalStateException(e);
-               }
+       static URI mavenRepoUrl(String repoBase, M2Artifact artifact) throws URISyntaxException {
+               String uri = artifactUrl(repoBase == null ? MAVEN_CENTRAL_BASE_URL : repoBase, artifact);
+               return new URI(uri);
        }
 
        /** Absolute path to the directories where the files will be stored */