I would like to create an installer for a library (DLL) that can be use in multiple system including MATLAB.
For MATLAB, I have additional *.m and *.mex files to make the DLL functions easily accessible from it.
I also have an installer that modify the PATH environment variable to make my DLL visible to all potential calling system.
My problem is that MATLAB does not make use of the system PATH environment variable. Thus, I am looking for a fix that would allow users of my library to run the installer and have my library accessible from MATLAB "out of the box" (possibly after a restart or session reopen).
I currently see 2 ways to do it which I both do not like :
Write a MATLAB script that uses addpath()/savepath() functions. I don't like this because :
a. MATLAB may not always be installed.
b. This would mess with the user's MATLAB's own path variable.
c. Upon installing a new version of my library, I would have to mess even more with the MATLAB's path to delete the path to older library before adding the path to the newer library.
Look through the system PATH and search for ...\MATLAB\RXXXXn\bin path to use that to install my *.m and *.mex files in the appropriate folder inside MATLAB. I don't like this because :
a. It would mess with MATLAB's own installation.
b. Once again, installation of multiple successive versions of the library may cause some issues (currently multiple version may be installed in separate directory, and the PATH redirects to the last one installed, experts users can modify the PATH according to their needs).
Currently, I am leaning towards option 2, but I am looking for a better, cleaner solution to this installation procedure.
Can anyone give me some MATLAB's expert advice ?
Thanks in advance for your help!
Related
Is there a way to create an equivalent of Python's virtual environments (virtualenv)? With virtualenvs, one can install Python packages inside the virtual environment (a separate directory) without messing up the global python environment. One can remove packages that one decides they don't need without worrying about removing a package that is depended upon by another Python project. I'm sure there are other benefits that I'm not thinking of at the moment. I notice that when I use chicken-install, it installs all of the eggs in my /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/ dir. Is there a way to have them install that egg in a project specific directory similarly to how Python's virtualenv works?
There isn't really such a thing in CHICKEN 4. The problem here is that installing eggs to a different location is one part, the other is running programs so that they look up eggs in that location. You can emulate it by using something along these lines:
export LOCAL_EGGS=/path/to/project/local
chicken-install -init $LOCAL_EGGS
export CHICKEN_REPOSITORY=$LOCAL_EGGS
chicken-install r7rs ...
csc ...
The easiest way to do this is to simply install CHICKEN to a different location using the PREFIX option to make when building it (see the README for instructions). This allows you to have a CHICKEN specifically built for each of your projects. I vastly prefer this option over the others because it is very easy to understand, and CHICKEN itself is very fast to build and not very big, so I find the overhead of doing this quite acceptable.
Alternatively, use what wasamasa proposed, or use the -deploy option to install eggs with the program. See the deployment chapter in the manual for more info.
Actually you don't need any "virtual environment" - everything already in place.
There is straightforward way to change repository location:
CHICKEN_INSTALL_REPOSITORY is the place where eggs will be installed and which the egg-related tools like chicken-install, chicken-uninstall and chicken-status consult and update. Make sure the paths given in these environment variables are absolute and not relative.
and
CHICKEN_REPOSITORY_PATH is a directory (or a list of directories separated by :/;) where eggs are to be loaded from for all chicken-based programs.
Point CHICKEN_INSTALL_REPOSITORY to the location where you want it to be. Note that you need to point CHICKEN_REPOSITORY_PATH to your local repository as well as system one in order to be able to import extensions distributed with Chicken system.
Also you most likely need to setup installation prefix:
An alternative installation prefix that will be prepended to extension installation paths if specified. It is set by the -prefix option or environment variable CHICKEN_INSTALL_PREFIX.
and update your PATH:
PATH="$CHICKEN_INSTALL_PREFIX/bin:$PATH"
This allows you to install extensions which provide console programs.
The only thing left to do is export all these variables.
That's it!
This is basically what Python's virtualenv activate script does in essence. As you can see, this is very simple steps to do. You don't need a dedicated tool to manage that. A very simple shell script can serve very well.
How it works?
This works by introducing an one more depth level local hierarchy, (as it does for /usr and /usr/local, please, see FHS). If you wonder what the hell is local hierarchy, take a look at your $HOME/.local - probably you have something interesting inside.
Bonus
As far as setting up per-project extensions repository involves only environment modification, this definitely can be automated. There is very handy tool to solve this kind of problems in general: direnv. Using this simple function in your $HOME/.envrc:
use_chicken() {
LOCAL=$(expand_path .local)
system_repository=$(chicken-install -repository)
binary_version=${system_repository##*/}
local_repository=${LOCAL}/lib/chicken/${binary_version}
path_add CHICKEN_REPOSITORY_PATH ${system_repository}
path_add CHICKEN_REPOSITORY_PATH ${local_repository}
export CHICKEN_REPOSITORY_PATH
export CHICKEN_INSTALL_REPOSITORY=${local_repository}
export CHICKEN_INSTALL_PREFIX=${LOCAL}
PATH_add ${LOCAL}/bin
}
you can setup your Chicken project just with these two lines in .envrc inside project directory:
source_up
use chicken
I know https://github.com/ursetto/cenv exists (never used it myself), and it is for CHICKEN 5 only, though (it won't work with CHICKEN 4). Thought about mentioning it in case you plan to migrate to CHICKEN 5.
A program uses a local-install approach and not a .msi installer and can't use an MSI module. If the win10 ucrt has been installed or is native, I don't want to add my own local copy. Likewise for the VS Redistributables: if the use has formally installed that previously or did so as a prior step, I want to know that, so if it has not been done, I can supply "local" versions.
The obvious idea is to try LoadLibraryEx with the default system search path. But I wonder if there is a call to ask if that's been installed properly, rather than possibly find a stray copy that happens to be on the path or whatnot.
With respect to external libraries and File Exchange packages, I'm trying to make my MATLAB code more compatible with the multiple systems I run it on.
For example, let's say I want to run my code on two differently setup Windows systems. The function depends on an external library not located within the current work directory, but rather as shown below:
System 1
addpath('C:/SomeFolders/Git/3rdParty/Library')
System 2
addpath('B:/Git/3rdParty/Library')
The current working folder for both would be '.../Git/ProjectFolder'
Is there a way to have MATLAB navigate ("go-up/down") the folder hierarchy levels and search for the desired library?
Cheers,
I have a go app which relies heavily on static resources like images and jars. I want to install that go executable in different platforms like linux, mac and windows.
I first thought of bundling the resources using https://github.com/jteeuwen/go-bindata, but since the files(~100) have size ~ 20MB or so, it takes a really long time to build the executable. I thought having a single executable is an easy way for people to download the executable and run it. But seems like that is not an effective way.
I then thought of writing a installation package for each of the platform like creating a .rpm or .deb packages? So these packages contain all the resources and puts it into some platform specific pre defined locations and the go executable can reference them. But the only thing is that I have to handle that in the go code. I have to see if it is windows then load the files from say c:\go-installs or if it is linux then load the files from say /usr/local/share/go-installs. I want the go code to be as platform agnostic as it can be.
Or is there some other strategy for this?
Thanks
Possibly does not qualify as real answer but still…
As to your point №2, one way to handle this is to exploit Go's way to do conditional compilation: you might create a set of files like res_linux.go, res_windows.go etc and put a set of the same variables in each, pointing to different locations, like
var InstallsPath = `C:\go-installs`
in res_windows.go and
var InstallsPath = `/usr/share/myapp`
in res_linux.go and so on. Then in the rest of the program just reference the res.InstallsPath variable and use the path/filepath package to construct full pathnames of actual resources.
Of course, another way to go is to do a runtime switch on runtime.GOOS variable—possibly in an init() function in one of the source files.
Pack everything in a zip archive and read your resource files from it using archive/zip. This way you'll have to distribute just two files—almost "xcopy deployment".
Note that while on Windows you could just have your executable extract the directory from the pathname of itself (os.Args[0]) and assume the resource file is located in the same directory, on POSIX platforms (GNU/Linux and *BSD etc) the resource file should still be located under /usr/share/myapp or a similar place dictated by FHS (or particular distro's rules), so some logic to locate that file will still be required.
All in all, if this is supposed to be a piece of FOSS, I'd go with the first variant to let the downstream packagers tweak the pathnames. If this is a proprietary (or just niche) software the second idea appears to be rather OK as you'll play the role of downstream packagers yourself.
I want to put my dependent files in the app directory.
I seem to remember that you can force VB6 to use the files in the local directory only.
Any hints?
You may also want to try setting up Reg-Free COM for your project. There's a freeware called Unattended Make My Manifest that will do most of the work for you.
Placing component libraries in the EXE folder (with or without .local files) can be deleterious to the hygiene of target machines too.
VB6 programs will register the components here via the self-reg entrypoint behind your back if they are not previously registered. Then if the application is moved or removed you leave the user with a broken reigistration - possibly fatal to subsequently installed applications using some of the same components. This is probably fine though for application specific components, i.e. your own DLL or OCX that will never be needed by another application.
The .local trick was really not meant for use with VB6 programs and if it is used your installer needs to be aware and properly install and register the components if they are not already on the machine. It was meant as a manual hack to get around DLL version compatibility problems on individual machines, not a deployment strategy.
Move up to SxS application and assembly manifests (Reg-Free COM and more) for a better solution. DLL/COM Redirection (.local) was a good try but it has many warts.
Clay Nichol's answer about the search order is not quite correct. That search order only applies to non-COM components. I.e. only some DLLs, and not OCXs. If you register your COM objects, they will be used from the directory where they are registered regardless of what's in the local directory, unless you use reg-free COM or a .local file.
EDIT:
MakeMyManifest is well spoken of as an automatic tool for creating manifests for VB6 projects, haven't tried it myself.
DirectCOM also has fans, again I haven't tried it.
EDIT The MMM website is down. I see here that the author was having trouble with their hosting and has provided another location to get Make My Manifest - download it here.
There is a semi-automatic technique to generate reg-free COM manifests. You can create the manifests with Visual Studio 2008 (you can use a free version like Visual Basic Express Edition). Then make a couple of edits by hand to make the manifests suitable for use from VB6. See this section of this MSDN article for step-by-step instructions - ignore the rest of the article which is about ClickOnce.
It can be sort of confusing because every version of windows, the rules change. Older versions of Windows search the path before the current directory.
A simple solution without manifests:
If your executable file is A.EXE, add a (0-byte, empty) file in the same directory named A.EXE.local -- for older versions of Windows this puts the app directory ahead of the path in the search order.
Found it myself:
Windows does look in the App Directory first:
If SafeDllSearchMode is enabled, the search order is as follows:
The directory from which the application loaded.
The system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The current directory.
The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.
If SafeDllSearchMode is disabled, the search order is as follows:
1. The directory from which the application loaded.
2. The current directory.
3. The system directory. Use the GetSystemDirectory function to get the path of this directory.
4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.
according to : http://msdn.microsoft.com/en-us/library/ms682586.aspx
But you can redirect where it looks for .dll's using a Manifest:
http://msdn.microsoft.com/en-us/library/aa375365(VS.85).aspx