Swift package Manager missing library after wrap - swift-package-manager

I'm trying to generate a wrapper around a C library for Swift but when I import it into my Xcode project I'm getting an error that
Missing required module 'Clibsodium'
I'm not sure where it's trying to get that name from. My wrapper has this for the Package.swift
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Sodium",
pkgConfig: "libsodium",
providers: [
.brew(["libsodium"]),
.apt(["libsodium-dev"])
]
)
And then my module.modulemap looks like so:
module Sodium [system] {
header "shim.h"
link "sodium"
export *
}
and shim.h just includes the proper header:
#ifndef CLIB_SWIFT_SODIUM
#define CLIB_SWIFT_SODIUM
#ifdef __APPLE__
#include "/usr/local/include/sodium.h"
#else
#include "/usr/include/sodium.h"
#endif
#endif
On my mac, if I run pkg-config --libs libsodium it says this:
-L/usr/local/Cellar/libsodium/1.0.16/lib -lsodium

I fixed the defining the Clibsodium lib as an explicit module. Doing that you can import it via the Sodium framework like import Sodium.Clibsodium and fixing with that the missing Missing required module 'Clibsodium'
I inspired my solution on:
In order to import C library into Swift, it first need to be be
declared as a module. Declaration takes the form of a module map — a
file describing headers to import and static libraries to link with.
The resulting module may be imported into Swift (natively) and
Objective-C (using #import keyword).
This way of embedding C library
into a framework will work for you in most cases (learn more about
this approach here and there). It is totally legit as long as you’re
developing some internal framework or simply modularising your
application into separate parts. However, it doesn’t work well when
you need to ship your library to external users via Carthage,
Cocoapods or as a binary. The main reason being that the resulting
framework is not portable between computers. When undergoing
compilation, your resulting framework is bound to the current location
of headers and libraries from module map on your computer. You can use
it right away in your project but should you try to send it to
somebody else they will not be able to link it to a project because
files referenced by module map are no longer accessible.
from this article where you can find step by step how to achieve it with the advantage and disadvantage of this approach.
Basically what you need to do is:
Create the Sodium.modulemap file and add it to the root of your project
Inside Sodium.modulemap you can define the Clibsodium library as an explicit module like:
framework module Sodium {
umbrella header "Sodium.h"
explicit module Clibsodium {
private header "version.h"
private header "crypto_pwhash_argon2id.h"
private header "export.h"
private header "core.h"
private header "crypto_aead_aes256gcm.h"
private header "crypto_aead_chacha20poly1305.h"
private header "crypto_aead_xchacha20poly1305.h"
private header "crypto_auth.h"
private header "crypto_auth_hmacsha256.h"
private header "crypto_auth_hmacsha512.h"
private header "crypto_auth_hmacsha512256.h"
private header "crypto_box.h"
private header "crypto_box_curve25519xsalsa20poly1305.h"
private header "crypto_core_hsalsa20.h"
private header "crypto_core_hchacha20.h"
private header "crypto_core_salsa20.h"
private header "crypto_core_salsa2012.h"
private header "crypto_core_salsa208.h"
private header "crypto_generichash.h"
private header "crypto_generichash_blake2b.h"
private header "crypto_hash.h"
private header "crypto_hash_sha256.h"
private header "crypto_hash_sha512.h"
private header "crypto_kdf.h"
private header "crypto_kdf_blake2b.h"
private header "crypto_kx.h"
private header "crypto_onetimeauth.h"
private header "crypto_onetimeauth_poly1305.h"
private header "crypto_pwhash.h"
private header "crypto_pwhash_argon2i.h"
private header "crypto_scalarmult.h"
private header "crypto_scalarmult_curve25519.h"
private header "crypto_secretbox.h"
private header "crypto_secretbox_xsalsa20poly1305.h"
private header "crypto_secretstream_xchacha20poly1305.h"
private header "crypto_shorthash.h"
private header "crypto_shorthash_siphash24.h"
private header "crypto_sign.h"
private header "crypto_sign_ed25519.h"
private header "crypto_stream.h"
private header "crypto_stream_chacha20.h"
private header "crypto_stream_salsa20.h"
private header "crypto_stream_xsalsa20.h"
private header "crypto_verify_16.h"
private header "crypto_verify_32.h"
private header "crypto_verify_64.h"
private header "randombytes.h"
private header "randombytes_internal_random.h"
private header "randombytes_sysrandom.h"
private header "runtime.h"
private header "utils.h"
}
export *
module * { export * }
}
Sodium.modulemap should not be added to any target and must be specified in Build Settings — Packaging — Module Map (MODULEMAP_FILE) = $SRCROOT/GifSwift/GifSwift.modulemap
Clibsodium files must be added to framework target as Private Header and linked static library (libsodium-x.a)
Replace the import Clibsodium statements with Sodium.Clibsodium
Now you can use the Sodium framework in any project without having the missing module error because Sodium will look for the library inside the .framework container

Related

Unable to call JNI exported functions in c# dotnetcore

I have a shared object file (.so) created for Java platform, written in cpp and auto generated from JNI. I want to utilize the same shared object file's exported methods in c# dotnet core as well.
Some methods are accessible via their mangled names and are being called correctly. Rest of the methods either dont have a mangled name attached to them or dont work.
I found out the symbols using nm -D /lib/file name
symbol examples:
000000000000c7d9 T Java_java_1shm_1wrapper_SharedMemWrapper_addAgent
000000000000c840 T Java_java_1shm_1wrapper_SharedMemWrapper_addAgent2
000000000000d279 T Java_java_1shm_1wrapper_SharedMemWrapper_addAgentACDAttribute
Symbols that are working example c# code:
[DllImport("jshmwrap", CharSet = CharSet.Auto, EntryPoint = "_ZN20StateSvcSharedMemCtl14_initSharedMemEiPKci")]
public static extern int initSharedMem(String svc_name);
Symbol not working:
[DllImport("jshmwrap.so", CharSet = CharSet.Auto, EntryPoint = "_ZN20StateSvcSharedMemCtl15getMessageQueueEPcii13enSMQSyncType")]
public static extern long getMessageQueue(String q_name, int create);
[DllImport("jshmwrap.so", CharSet = CharSet.Auto)]
public static extern int Java_java_1shm_1wrapper_SharedMemWrapper_initSharedMem(String svc_name);
What am I missing here? Why do some mangled names work and others do not? Also, why don't exported function names work?

library module upgrade to Glide 4, where should the AppGlideModule be put in

In library module to upgrade to Glide 4.9.0.
api "com.github.bumptech.glide:glide:4.9.0"
api "com.github.bumptech.glide:annotations:4.9.0"
annotationProcessor "com.github.bumptech.glide:compiler:4.9.0"
and having a kotlin extension
fun ImageView.loadImg(imageUrl: String) {
// 4.+ code
var requestOptions : RequestOptions = RequestOptions()
.placeholder(ColorDrawable(Color.LTGRAY))
.diskCacheStrategy(DiskCacheStrategy.ALL)
if (!TextUtils.isEmpty(imageUrl)) {
Glide.with(context)
.setDefaultRequestOptions(requestOptions) // or use .apply(requestOptions) but after the .load()
.asBitmap()
.load(imageUrl)
.into(this)
}
}
but it crashes
java.lang.AbstractMethodError: abstract method "void com.bumptech.glide.module.RegistersComponents.registerComponents(android.content.Context, com.bumptech.glide.Glide, com.bumptech.glide.Registry)"
at com.bumptech.glide.Glide.initializeGlide(Glide.java:270)
at com.bumptech.glide.Glide.initializeGlide(Glide.java:223)
at com.bumptech.glide.Glide.checkAndInitializeGlide(Glide.java:184)
at com.bumptech.glide.Glide.get(Glide.java:168)
at com.bumptech.glide.Glide.getRetriever(Glide.java:689)
at com.bumptech.glide.Glide.with(Glide.java:716)
at com.common.extentions.ExtensionsKt.loadImg(Extensions.kt:44)
After adding
#GlideModule
class TheAppGlideModule : AppGlideModule() {
override fun isManifestParsingEnabled(): Boolean {
return false
}
}
to the library module does not help, or adding it to hosting app only does not work either,
but after adding it to both the library module and the hosting app the crash goes away.
according to documentation https://bumptech.github.io/glide/doc/generatedapi.html,
isnt it that it not supposed to have this class defined in the library module?
anyone has same experience?
* For now the API is only generated when a properly annotated AppGlideModule is found.
* There can only be one AppGlideModule per application.
* As a result it’s not possible to generate the API for a library without precluding any application
* that uses the library from using the generated API.
Resolved, it has missed
api "com.github.bumptech.glide:annotations:$versions.glide"
in the application side (not sure why adding single one in the module did not work and why with both it worked, maybe didnt do clear/rebuild after change?)

Loading a Symfony parameter in the AppKernel

We need to store our cache and log files outside of the project folder structure. I have set up parameters_prod.yml and parameters_dev.yml that will be build by Bamboo on deployment to different servers/environments.
Is there any way that I can access these parameters in the AppKernal so that I can use them in the getCacheDir() function? This would be the easy way of doing things short of parsing them myself or something.
So the final directory structure should look the same as the default Symfony one, with the exception of the cache and logs. The server team has requested that the cache and logs should be under var/tmp and var/logs. So for an application, the cache would be /var/tmp/symfony/projectName/prod and /var/tmp/symfony/projectName/dev. Logs would follow a similar structure.
So basically the structure would follow the normal Symfony one except /var/www/Symfony/projectName/var/cache becomes /var/tmp/symfony/projectName and /var/www/Symfony/projectName/var/logs becomes /var/logs/symfony/projectName. Note that all these locations here are absolute (and the location of the root of the project may differ slightly, when Bamboo deploys, it will set up the correct paths etc).
One of the strange things is that when I set it up like this, the site actually runs, but I can not see anything under the new cache location (have not started working on the logs side yet). So there has to be cache files somewhere, but a locate doesn't even find them!
NOTE: I have now found that if you run the internal server, this problem doesn't happen. This only happens if you are loading the site under Apache.
The problem with your idea is that a service container and parameters are initialized just moment after the ConfigCache object has been constructed, with a absolute cache path as parameter.
namespace Symfony\Component\HttpKernel;
...
/**
* The Kernel is the heart of the Symfony system.
*
* It manages an environment made of bundles.
*
* #author Fabien Potencier <fabien#symfony.com>
*/
abstract class Kernel implements KernelInterface, TerminableInterface
{
...
/**
* Initializes the service container.
*
* The cached version of the service container is used when fresh, otherwise the
* container is built.
*/
protected function initializeContainer()
{
$class = $this->getContainerClass();
// !!!!!! cache config object construction
$cache = new ConfigCache($this->getCacheDir().'/'.$class.'.php', $this->debug);
$fresh = true;
if (!$cache->isFresh()) {
$container = $this->buildContainer();
$container->compile();
$this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
$fresh = false;
}
require_once $cache->getPath();
$this->container = new $class();
$this->container->set('kernel', $this);
if (!$fresh && $this->container->has('cache_warmer')) {
$this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'));
}
}
}
So, you can't have access to your custom defined parameters in a getCacheDir() method.
Could you override the getCacheDir() method?
Let's say that your directory structure looks like this
-home
--symfony_app
--custom_cache_directory
Than method override would look something like this:
public function getCacheDir()
{
return dirname(__DIR__).'/../custom_cache_directory/cache/'.$this->getEnvironment();
}
More info at official docs: http://symfony.com/doc/current/configuration/override_dir_structure.html#override-the-cache-directory
So the answer is to do as Matko suggested, and DON'T use the /var/tmp directory.
So in /appName/app/AppKernel.php I edited the getCacheDir() to make it look more like:
public function getCacheDir()
{
return '/var/symfony/cache/projectName' . '/' . $this->getEnvironment();
}
or whatever path you want to use.
Don't use anything under /tmp or /var/tmp (I'm on RHEL) as these folders do some weird things (/var/tmp seemed to never actually write the cache to disk).

Spring-boot return json and xml from controllers

I have a spring-boot 1.1.7 application that uses Thymeleaf for much of the UI, so the response from my controllers hasn't really been a concern. However, now I need to provide a XML response when a user submits a request via URL.
Here is a typical Request:
http://localhost:9001/remote/search?sdnName=Victoria&address=123 Maple Ave
Here is most of my gradle configuration:
project.ext {
springBootVersion = '1.1.7.RELEASE'
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion")
compile("org.springframework.security:spring-security-web:4.0.0.M1")
compile("org.springframework.security:spring-security-config:4.0.0.M1")
compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity3:2.1.1.RELEASE')
compile("org.springframework.boot:spring-boot-starter-actuator")
compile('com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.0')
}
And here is my controller:
#Controller
public class RemoteSearchController {
#Autowired
private SdnSearchService sdnSearchService;
#RequestMapping(value = "/remote/search", method = RequestMethod.GET, produces = MediaType.APPLICATION_XML_VALUE)
public List<Sdn> search(#ModelAttribute SdnSearch sdnSearch) {
List<Sdn> foundSdns = sdnSearchService.find( sdnSearch );
return foundSdns;
}
Here is my Object to be returned:
#Entity
public class Sdn {
#Id
private long entNum;
private String sdnName;
...
//getters & setters here
}
I am able to receive the request via REST client (such as CocoaREST) and handle it. But When I return the list of SDN i get the following exception, even though I do have Jackson & jackson-dataformat-xml on my classpath:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:229)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:301)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:248)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:57)
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:299)
My REST Client is including a Accept Header of "text/xml" (but in all honesty I would rather them not have to set this. Ideally any call to this Controller would always get XML, regardless of header being present).
Is there a way to handle this? I thought the Media Converters were included and just returned whatever the controller told them to?
SOLUTION:
See below for the answer I posted.
I had the exact same problem and I found the solution on Spring documentation website : here
In synthesis, I added the following dependency to the pom.xml of my project :
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
Then I added the following code block to the class that the service had to return :
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Greeting {...}
And it worked.
SOLUTION: I used a combination of both answers below (thank you very much!). I am posting here in case anyone else needs help.
My modified controller:
#Controller
public class RemoteSearchController {
#Autowired
private SdnSearchService sdnSearchService;
#RequestMapping(value = "/remote/search", method = RequestMethod.GET, produces = { "application/xml", "text/xml" }, consumes = MediaType.ALL_VALUE )
#ResponseBody
public SdnSearchResults search(#ModelAttribute SdnSearch sdnSearch) {
List<Sdn> foundSdns = sdnSearchService.find( sdnSearch );
SdnSearchResults results = new SdnSearchResults();
results.setSdns( foundSdns );
return results;
}
}
And on my client, I set the request headers:
Content-type: application/text
Accept: text/xml
I think ultimately the problem was that my client headers were not being set correctly, so I may not have had to make some of these changes. But I liked the idea of a SearchResults class containing a list of results:
#XmlRootElement
public class SdnSearchResults {
private List<Sdn> sdns;
...
}
It may be better to create a new class:
public class SdnSearchResult {
private List<Sdn> sdns;
...
}
Then, a slight change will be required to the existing classes as follows:
public interface SdnSearchService {
SdnSearchResult find(SdnSearch sdnSearch);
}
#Controller
public class UISearchController {
#Autowired
private SdnSearchService sdnSearchService;
#RequestMapping("/search")
public ModelAndView search(#ModelAttribute SdnSearch sdnSearch) {
return new ModelAndView("pages/search/results", "sdns", sdnSearchService.find(sdnSearch).getSdns());
}
}
Once this is done, the other controller must be coded as:
#Controller
public class RemoteSearchController {
#Autowired
private SdnSearchService sdnSearchService;
#RequestMapping("/remote/search")
#ResponseBody
public SdnSearchResult search(#RequestBody SdnSearch sdnSearch) {
return sdnSearchService.find(sdnSearch);
}
}
A quick explanation of the changes from your code:
#RequestBody will automatically deserialize the entire HTTP request body to an SdnSearch instance. External applications will typically submit the request data as HTTP body, so #RequestBody will ensure that the deserialization to Java object happens automatically.
#ResponseBody will automatically serialize the return value according to the external client's capabilities and the libraries available on the classpath. If Jackson is available on the classpath and the client has indicated that they can accept JSON, the return value will be automatically sent as JSON. If the JRE is 1.7 or higher (which means that JAXB is included with the JRE) and the client has indicated that they can accept XML, the return value will be automatically sent as XML.
List<Sdn> needs to be changed to SdnSearchResult to ensure that the application can exchange JSON, XML, RSS and ATOM formats with a single controller method, since XML (and XML based formats) require a root-tag on the output, which a List<Sdn> cannot be translated to.
Once these changes are done, fire up a REST client such as the Postman extension for Chrome and submit a request to /remote/search with the following information:
Request header Accepts set to application/json.
Request header Content-Type set to application/json.
Request body set to the JSON string { "sdnName" : "Victoria", "address" : "123 Maple Ave" }.
This will give you a JSON response.
You've marked the controller method as producing application/xml responses (produces = MediaType.APPLICATION_XML_VALUE). The request's accept header (Accept: text/xml) doesn't match so Spring determines that your search method cannot handle the request.
There are a few different ways to fix this on the server, depending on your exact requirements:
You could remove the produces attribute entirely
You could specify multiple media types: produces = { "application/xml", "text/xml" }
I am not sure about your version of Spring Boot (1.1.7.RELEASE) but I am on version 1.5.2.RELEASE and this xml conversion / serialization happens automatically without usage of any jackson dependencies as mentioned in few of the answers.
I guess that is happening because org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter is automatically configured since Spring Boot version 1.5.1.RELEASE & that converter uses default JAXB implementation of JRE ( so no explicit xml conversion dependency needed ) .
Second, Accept header set by clients in request decides which format the output is expected so a request mapping like below ( i.e. a single end point ) ,
#RequestMapping(method = RequestMethod.GET, value = "/remote/search", produces = {
MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE })
can be used to produce an xml as well as a JSON response ( if Accept header is set as text/xml or application/xml & application/json respectively.
Note 1 : javax.xml.bind.annotation.XmlRootElement needs to be specified on root class if xml response is expected for a Java class. This is mandatory.
Note 2 : Jackson for json is already included in Spring Boot so that is not to be explicitly included for json outputs
Note 3 : Accept header - Output match off happens automatically by framework & developer doesn't have to code anything specific for that.
So in my opinion, if you only add XmlRootElement to your base class & upgrade your Spring Boot version, your server side is all set. Responsibility to set correct Accept header lies with the clients.
In addition to what Michael told in his answer, I added the following dependencies as well to pom.xml
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<version>4.4.1</version>
</dependency>
For some reason, the jackson-dataformat-xml alone was not helping.
I also made sure that ResponseEntity is returned in the get call and removed the produces=MediaType from the RequestMapping annotation.
With these changes, I was able to get the correct data but I had to give the extension of mime type to the REST URL during get call. ie, specify explicitly like: http://localhost:8080/hello.xml or http://localhost:8080/hello.json in browser
In my case I wanted to return a formatted XML string and it was all combined into one line.
Adding produces = { "application/xml", "text/xml" } to the request mapping was enough to return the string as formatted XML (with indentation).
example:
#RequestMapping(method= RequestMethod.GET, value="/generate/{blabla}", produces = { "application/xml", "text/xml" })
public String getBlaBla(#PathVariable("param") String param) throws IOException {
}
Goodluck.

Sonar and Flex plugin - Dollars ($) are not accepted in java class names

In reference to this bug from Sonar:
http://jira.codehaus.org/browse/SONAR-1865
and this one (which cross references the one above):
http://jira.codehaus.org/browse/SONAR-1637
I am still seeing this issue.
I am using Sonar server version 2.12.
I am using Hudson, version 2.2.0.
I have installed the Sonar plugin in Hudson, version 1.7.2.
and, most importantly, I have the Flex plugin installed in the Sonar server. Flex plugin version is 0.4.
When I run mvn sonar:sonar -Pflex on a flex project, i get this error in the stack trace:
Caused by: java.lang.IllegalArgumentException: Java inner classes are not supported : EntityEnums$ReportParameterName
at org.sonar.plugins.flex.FlexFile.<init>(FlexFile.java:79)
at org.sonar.plugins.flex.FlexFile.fromIOFile(FlexFile.java:165)
at org.sonar.plugins.flex.FlexSourceImporter.createResource(FlexSourceImporter.java:37)
at org.sonar.api.batch.AbstractSourceImporter.parseDirs(AbstractSourceImporter.java:75)
at org.sonar.api.batch.AbstractSourceImporter.analyse(AbstractSourceImporter.java:69)
at org.sonar.api.batch.AbstractSourceImporter.analyse(AbstractSourceImporter.java:60)
at org.sonar.batch.phases.SensorsExecutor.execute(SensorsExecutor.java:64)
Here is what my class looks like, that it is complaining about:
This is an Actionscript class, file name: EntityEnums$ReportParameterName.as. It was auto-generated from java to Actionscript using GraniteDS.
package com.digabit.core.db.entity.util {
[Bindable]
public class EntityEnums$ReportParameterName {
public static const tnid:String = "tnid";
public static const uname:String = "uname";
public static const lc:String = "lc";
public static const tnkey:String = "tnkey";
public static const oid:String = "oid";
public function EntityEnums$ReportParameterName()
{
super();
}
}
}
So, according the bug reports, this has been fixed in an earlier version of Sonar that I have; but I'm still seeing it in version 2.12. And why would the error show "java inner classes..." when this is a flex/actionscript class? Is anyone still seeing this bug behavior?
Issue has been created on Sonar Flex Plugin side ( http://jira.codehaus.org/browse/SONARPLUGINS-1623 ) and most probably would be fixed in next release.

Resources