Appimage problems - ruby

I would like to release my program that wrote in ruby language, I need to pack ruby to appimage file and send it to my client ubuntu PC first.
so I create the folder "ruby-img", then copy my compiled ruby which in "/app/ruby" folder to "ruby-img/app/ruby" and then made a link as "ln -r -s app/ruby/bin/ruby usr/bin/." in "ruby-img" folder.
then I create the desktop file and put png file to "ruby-img", using appimagetool to create ruby-x86_64.AppImage. sadly it can not run, AFAIK that ruby.AppImage still using /app/ruby/lib folder to find some library of ruby but not in "ruby-img/app/ruby/lib" related folder.
so I tried re-compile ruby as --prefix=/tmp/ruby or --prefix=/usr/local/ruby, then copy them to "ruby-img/usr/local/ruby" or "ruby-img/tmp/ruby" then maka some link as above, and repack to AppImage but ruby.AppImage still not working...
any idea can help me ?

AppImages contain of a filesystem with all the content you provide plus a small executable stub that will mount the AppImage filesystem, then run the AppRun executable to be found inside.
With that knowledge it is utmost important that you provide an executable in the root directory along with the .desktop and icon files. I suggest you do not create AppRun yourself. Use the precompiled one from https://github.com/AppImage/AppImageKit/releases/tag/continuous (do not forget to rename it to exactly 'AppRun').
Now when this AppRun gets invoked, it will perform a few checks, cd into the /usr directory and try to start the executable specified in the .desktop file. Check it's source code and you can see that it also sets a few environment variables.
Therefore it is best you provide your entrypoint as /usr/bin/ruby.sh and register that in the desktop file. Remember if /usr/bin/ruby.sh gets called, the current work directory is /usr. So ruby.sh can set further environment variables such as LD_LIBRARY_PATH so that the libraries you configured for /usr/lib will actually be loaded.
With that I hope you have at least as much success as I had.

Related

How to package shell programs into an AppImage?

I have made an AppImage via:
linuxdeploy --appdir AppDir --icon-file icon.png --desktop-file desktop.desktop --executable myExecutable --output appimage
which runs fine. However, the program I've packaged (myExecutable) makes shell calls (say to shellProgram1, shellProgram2, ...) at run-time to make use of various programs that aren't necessarily on every distro.
Question: Does linuxdeploy (or some other AppImage utility) provide an easy way to package these programs into the AppImage, so that when myExecutable calls them at run-time, they are guaranteed to be available?
To achieve such thing you need to deploy all the binaries that may not be present in all distros into the AppDir and set the PATH environment to make them available at runtime.
With linuxdeploy you have to manually copy the files into the AppDir and create a wrapper for the main binary to set the PATH. Something like this
$!/bin/bash
export PATH="$APPDIR/usr/bin:$PATH"
exec $APPDIR/usr/bin/my_program
You can also use appimage-builder which creates such wrapper for you. In the project examples folder, you can find several recipes that can be used for inspiration.

pyinstaller and simplehttpserver on OSX vs WIN

I've made a simple server based on another thread here on SO: Shutting down python TCPServer by custom handler
I wrapped this up into an .exe using pyinstaller like so:
pyinstaller C:\PATH TO FILE\server.py --distpath=\PATH TO FILE\ --onedir --onefile --noconsole
This works wonderfully on Windows (currently testing on Win 7 x64). I can copy this exe to any folder and get a webserver at that location. I did it this way because I am wrapping this up into a process that would be distributed with another application. The users of this application might not have python installed and they might have a browser that blocks the types of things I would like to serve during the application process.
This should also work on osx, but when I try to wrap the same python script with pyinstaller, instead of serving up the current directory, I get a server at my /Users/Username location and not the directory from where the app was run.
My process to get this to work on both Win and OSX was to begin from the python shell and run the scripts there. This works on both platforms. If I use Terminal, cd to the directory where I want to serve files, and run the python script from there, things work fine. But any attempt I make to wrap the script into something executable leads me back to the same result of serving from /Users/Username, so I'm obviously missing something fundamental of how the wrapping is working. I am assuming it has to do with shell scripting and the script being tied to the current user?
I'd like to continue to use pyinstaller for this process since it would be the same process on Windows and OSX, but I cannot seem to get the resulting app to serve files from the directory from which it is run. Any guidance on what is happening, and how to fix it through pyinstaller (or other method) would be greatly appreciated.
#tallforasmurf on the pyinstaller Github pointed out that I missed something in the pyinstaller docs that is very important:
Adapting to being "frozen"
In some apps it is necessary to learn at run-time whether the app is
running "live" (from source) or "frozen" (part of a bundle). For
example, you might have a configuration file that, when running
"live", is found based on a module's file attribute. That won't
work when the code is bundled.
When your application needs access to a data file, for example a
configuration file or an icon image file, you get the path to the file
with the following code:
import sys
import os
...
if getattr(sys, 'frozen', False):
# we are running in a |PyInstaller| bundle
basedir = sys._MEIPASS
else:
# we are running in a normal Python environment
basedir = os.path.dirname(__file__)
The PyInstaller bootloader adds the attribute frozen to the sys
module. If that attribute exists, your script has been launched by the
bootloader. When that is true, sys._MEIPASS (note the underscore in
the name) contains the path to the folder containing your script and
any other files or folders bundled with it. For one-folder mode this
is the distribution folder. For one-file mode it is the temporary
folder created by the bootloader .
When your program was not started by the bootloader, the standard
Python variable file is the full path to the script now executing,
and os.path.dirname() extracts the path to the folder that contains
it.
I was able to os.chdir(basedir) after going up a few levels past the .app bundle directory and properly serve the files in the same directory as the .app bundle.

ImageMagick deployment on Mac OS

I'm trying to deploy ImageMagick with my own software. On windows I've just included all the core dlls with coders dlls at the exe path and it works well.
But on mac os I have troubles with coders. I installed ImageMagick via macports and found it with the help of CMake. CMake does all the job of copying and fixing up all the core libs I've linked against. Then I copied all the coder libs and fixed them up also, but when I start my application it just can't find any coder. So I'd like to know what am I missing there.
Note: if I didn't fix up any paths it works well. It is only my deployment that is in trouble. Maybe I should include some kind of config file?
P.S. I have all ImageMagick libs including coders SOs near the executable in MacOS bundle sub-folder.
How about setting the MAGICK_CODER_MODULE_PATH in your bundle?
see here: http://www.imagemagick.org/script/resources.php
EDIT:
To improve the information:
Originally when embedding IM in our own app bundle we had three problems:
our app and the IM dylibs not finding referenced IM dylibs,
IM not finding its config files,
IM not finding coders (the No Decode Delegate error)
We tried changing the hardcoded paths in the dylibs using the install_name_tool but finally when doing some tests with moving the IM around to different directories and testing
convert -debug configuration
we found out the all three above problems could be solved just by setting and exporting at least these three environment variables in the terminal console before running convert:
DYLD_LIBRARY_PATH
MAGICK_CONFIGURE_PATH
MAGICK_CODER_MODULE_PATH
With this experience, we returned back to our bundle and in the beginning tried to use the Info.plist fiel to set these variables but it didn't seem to work - probably because there were problems with making the paths to IM inside the bundle relative.
Finally we created a simple sh script and put it into our bundle and configured this bundle to run this script instead of the main app:
#!/bin/sh
CURR_DIR="$( cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
IMAGE_MAGICK_PATH=$CURR_DIR/../Resources/ImageMagick
export DYLD_LIBRARY_PATH=$IMAGE_MAGICK_PATH/lib
export MAGICK_CONFIGURE_PATH=$IMAGE_MAGICK_PATH/lib/ImageMagick-6.8.0/config
export MAGICK_CODER_MODULE_PATH=$IMAGE_MAGICK_PATH/lib/ImageMagick-6.8.0/modules-Q16/coders
# run application
exec $CURR_DIR/OurAppName
The key thing to make it working was properly getting the CURR_DIR of the app bundle (thanks to this post).
And as came out of our tests, setting the environment variables this way makes them visible only for this application execution context - i.e. when we started our app using the bundle, opened terminal and typed
env
the above three variables were missing from the output.
Hope this will help others save couple of days of research and pulling hairs out of their heads ;)
I've found a full solution for deploying ImageMagick in a bundle with the help of CMake. If you don't use CMake then #Tomasz's answer will be of help also.
So let's start:
First of all you need to know what and where ImageMagick is trying to locate when it is used from your own code. To find it out you can use MAGICK_DEBUG environmental variable which could be set to those parameters. It really helps when you debug ImageMagick.
Prerequisites:
I assume that you used FIND_PACKAGE and FIXUP_BUNDLE to find ImageMagick and set its binary paths inside the bundle. The only thing left is to deploy coders. Also I assume that you've installed ImageMagick from Mac Ports.
We need to get ImageMagick version string to correctly locate the coders:
STRING(REGEX REPLACE "-.+" "" ImageMagick_SHORT_VERSION ${ImageMagick_VERSION_STRING})
Now ImageMagick_SHORT_VERSION contains full version without any sub versions.
Then we need to copy all the coders to some predefined folder(I've used ImageMagick/coders subfolder under MacOS part of the bundle)
FILE(COPY /opt/local/lib/ImageMagick-${ImageMagick_SHORT_VERSION}/modules-Q16/coders/ DESTINATION ${PATH_TO_YOUR_BUNDLE}/Contents/MacOS/ImageMagick/coders/)
Now we need to fixup all the *.so libs we have, so we list it and pass to fixup_bundle
FILE(GLOB IMAGEMAGICK_CODERS ${PATH_TO_YOUR_BUNDLE}/Contents/MacOS/ImageMagick/coders/*.so)
Now we should update *.la files which accompanies coders *.so. To achieve it I've used script:
INSTALL(SCRIPT LaScript.cmake COMPONENT Runtime)
Script content:
SET(TARGET_BINARY_DIR "${PATH_TO_YOUR_BUNDLE}")
FILE(GLOB IMAGEMAGICK_CODERS_LA ${TARGET_BINARY_DIR}/Contents/MacOS/ImageMagick/coders/*.la)
FOREACH(file ${IMAGEMAGICK_CODERS_LA})
FILE(READ ${file} FILE_CONTENT)
STRING(REGEX REPLACE "dependency_libs='.*'" " " MODIFIED_FILE_CONTENT ${FILE_CONTENT})
STRING(REGEX REPLACE "libdir='.*'" " " MODIFIED_FILE_CONTENT ${MODIFIED_FILE_CONTENT})
FILE(WRITE ${file} ${MODIFIED_FILE_CONTENT})
ENDFOREACH()
We almost ready the only thing left to be done is to change the way we launch the application. But let's digress a little bit and find out where ImageMagick searches for the coders:
It tries to get the content of MAGICK_CODER_MODULE_PATH environmental variable
Then it checks if MAGICKCORE_CODER_PATH macro is defined(and in fact it does!) and use its value.
Then it will try to use MAGICK_HOME environmental variable and MAGICKCORE_CODER_RELATIVE_PATH to get path to the modules but we don't care since we will stop on #2 anyway!(NOTE: that it is true for Mac Ports installation)
So the only way we can interfere with search is to set MAGICK_CODER_MODULE_PATH environmental variable(Well we can also edit libMagickCodre and replace MAGICKCORE_CODER_PATH with some static path we need but it is too britle way to do things and it won't save us if someone set MAGICK_CODER_MODULE_PATH anyway)
We shouldn't set it system wide since we can break some user installtion so we have 2 options:
Use LSEnvironment to set the MAGICK_CODER_MODULE_PATH to some predefined location
Use script to launch our app and set this variable inside it.
I've chose the later since it is more flexible,
I have the following script:
#!/bin/bash
working_dir="${0%/*}"
export MAGICK_CODER_MODULE_PATH=$working_dir/ImageMagick/coders
executable="${working_dir}/ApplicationName"
"$executable"
and set CFBundleExecutable to the name of the script.
That's all and I hope it will help someone to save his/her time.
You should follow the Mac OS X-specific Build instructions but specifying --enable-shared in the configure options (see this document for details).
I guess that your application can't find the codecs because they have been statically linked to ImageMagick tools. This is usually done to address portability issues. To make codecs available in your application, you should build them as shared objects.

Creating .deb to install bash script program

I was wondering if the following is possible.
I have a BASH script that I want to make available for some people but I wanted them to only have to "install" the program and not messing around with terminal, so I thought a .deb would be cool.
So what would the "install" do?
Simple. I want to move the script and an icon to a folder (any folder, but I was wondering some hidden folder in Home) and then run a script that creates a launcher in the Applications menu for the first script. It seems there isn't much to it, but for what I've searched, there doesn't seem to be a lot of info...
How can I accomplish this?
By the way, I'm using Ubuntu 11.04.
Basically (install and) run dh-make to set up the debian/ directory, edit the generated files (mainly remove the many you do not need, and fill in a package description and any dependencies in debian/control), then debuild-us -uc -b.
You may also have to set up a simple Makefile for debian/rules to call; it probably only needs an install target to copy the binary to $(DESTDIR)/usr/bin.
Binaries install into /usr/bin and you should not try to override that. The way to have a menu is to add a .desktop file.
Once you have a good .deb you will need to set up a repo for distributing it. The simplest solution is probably to set up a launchpad.net account and create a personal PPA there.
It's not hard to find more information on these topics, but of course, you need to know what to look for. The canonical documentation is the Debian New Maintainer's Guide.
Found this video on youtube that explains IN FULL the process of creating a *.deb for a script or program and even mentions how to do it for a C program.
Full guide in how to build simple *.deb package
Has one bug, btw, that the author, during the making of the *.deb, didn't notice. The path in the *.desktop file for the EXEC parameter is wrong in the example.

Trying to access the "current dir" in a packaged Shoes app

I need to build an app which reads a file which is external to the Shoes package I'll be distributing it in.
In my app, Dir.pwd points to the temp dir (at least in Windows) where the script is unpacked to be ran. I've been trying to get the directory where the exe is running from, that is, the package I'm distributing.
The app needs to read a file which is distributed besides this package and then write another one in the same directory.
It seems that the Shoes runtime does not set any env variable with this directory either. Any pointers?
nachokb
I run into this problem a while ago and hadn't file a straight solution. I ended up with two workarounds:
At application installation time, put the files at a directory inside of the user home dir ~/ (the home indirection also works in windows)
Package the files together with the shoes generated executable so that it is unzip at the same place as the app and therefore accessible with Dir.pwd
If you find another way, please point it out.
Have you tried something like the following:
DIR = File.expand_path __FILE__
__FILE__ is a reference to the current file and File.expand_path gives you the full system path. Works in my shoes apps :-)
Shoes on!
Tobi

Resources