I have figured out that in a basic project I simply have to call the main package (m file) from the notebook using

<<nameofmfile`

and then the notebook recognizes the functions I defined in the m file and I can use these function in the notebook.

Unfortunately when I do the exact same thing in an application project the notebook doesn't recognize the main package (m file). I can't find proper help with this - the Workbench help doesn't seem too useful to me. I have a feeling that this problem occurs because the main package is not in the same folder as the notebook in the case of application projects. Please help!

1 Answer
1

Preamble

I feel that this question deserves an answer, since there are a few subtleties associated with WB development which may not be very well reflected in the WB documentation and can be confusing at first.

The mechanics of package search / loading in application projects

The standard structure of the WB application project usually contains nested directories, often with the same name. For example, here is the layout of the simplest application project:

Test
Test
Kernel
init.m
Test.m
Test.nb

My main point is that for such projects, the mechanism of locating and loading packages is different from just single-package projects. Namely, when you call Get["Test`"] or Needs["Test`"], then in addition to packages with the name Test.m,Mathematica also searches for directories with name Test present inside any of the directories currently on the $Path variable. And if it finds such a directory, it searches for the init.m file, which should be located in the Kernel subdirectory. If it is found, it is loaded.

So, for an application project, it is this init.m file that controls the way the packages of the project are loaded. If you look at the (autogenerated) init.m file for the above sample project, it has the following contents:

(* Mathematica Init File *)
Get[ "Test`Test`"]

Note that what is being loaded is referred to as Test`Test`. However, the resulting context will be just Test`, which can look puzzling at first. What really happens is that the Test.m file is in another Test sub-folder, so for Get to find it, it is mapped to Test`Test` rather than just Test` (the "left" Test` stands for sub-folder, and the "right" Test` for the file itself).

Likewise, you can use init.m file to implement an arbitrarily complex and completely customized way that component packages from you project are loaded. And, the context names used in init.m do not necessarily have to match the actual context names that end up being associated with those files - this gives another level of flexibility.

Workbench specifics

When you work from within WorkBench, then, when you click on the project's notebook, WorkBench launches the Mathematica kernel with a modified $Path variable, which now contains the root folder of your project (the outermost Test folder for the example above). This allows you to just call

Needs["Test`"]

from within the notebook and your project packages are loaded via the init.m mechanism (note that again, this is not the same as search for an individual package with the name Test.m, which is probably what you assumed and what people commonly think is happening).

When you click on "Run As Mathematica" or "Debug As Mathematica", then the default behavior is that you project is already loaded, so you can work with your notebook without even loading the project explicitly. You can have more precise control over what happens there by right-clicking on the project root folder, going to Properties -> Mathematica, and modifying the Execution Build Command field there.

Why it didn't work

In any case, this should explain why you were having trouble loading the project. I assume that you were loading the project notebook (or any other notebook) not within the WorkBench. In this case, the $Path variable does not contain the root folder of your project when Mathematica is launched stand-alone. Therefore, Mathematica has no way to find your project.

For most cases, I would recommend to work from within Workbench, so that this problem does not occur. If you really want to work with stand-alone Mathematica (which sometimes is indeed a better option, but such cases are rare), then you have two choices:

Copy your project to some of the default locations where Mathematica can find it, such as $UserBaseDirectory/Applications (but see the caveat below).

Add the path to the root folder of your application project to the $Path variable prior to loading the project.

The former option is a better one, but to make it work one may need additional steps and changes to the project layout, as discussed below. The latter option is really a quick hack, which might be OK during development but is a dead-end if you plan to deploy the project so that some other people can install it on their machines, since modifying the $Path variable is really not the way to go.

Application project layouts

When you create an application project, it is in a way a statement that you need to have a more complex project structure than a single package can offer. You may want to do this for a number of reasons, such as the need to accommodate additional resource files, split a project into several packages, or when your project has non-Mathematica components (such as Java or C code etc).

Very often then, the layout of the final project you deploy is different from the layout of your WB project, and this is right, since generally the mapping between your WB project and the final deployed one will be non-trivial. To construct the final layout, usually some build tools are used. I use Apache Ant, which is a good old tool, well-intergated into Eclispe / WB, but you are free to use other build tools such as e.g. Maven.

Why is this relevant to this discussion? Because if you simply copy the WB project into say $UserBaseDirectory/Applications, Mathematica won't find it. Rather, what should likely be the final layout will look something like this (for the example above):

Test
Kernel
init.m
Test.m

which is (in this simple case) the "inner part" of the WB project, but in more complicated cases it will be a less trivial rearrangement of the original project. What matters here is that we are one Test folder short here w.r.t. the original project, and this is what will allow Mathematica to find it in $UserBaseDirectory/Applications, since the number of Test-s is now right, so to speak (remember that the WB-initiated kernel has the root of your WB project added to the $Path, while for a stand-alone project, only $UserBaseDirectory/Applications is on the $Path, that's why it is different when you work from within WB).

The standard way to do this sort of layout rearrangements is to write an Ant script which would have targets such as "build" and "deploy", the former to create the needed directory structure in some temporary local directory within the project (say "Build"), and the latter to copy the resulting layout to whatever final destination you want it to be (e.g. $UserBaseDirectory/Applications).

If you follow these steps, then your workflow is as follows:

Make modifications to your sources

Run the build script

Re-launch Mathematica kernel

This allows you to work with your project using the stand-alone Mathematica session, but the price to pay is the longer turnaround between your changes and the notebook / FrontEnd work. I personally usually use both ways, but take some shortcuts and try to work from within Workbench most of the time since the turnaround is much faster. However, for projects you want to deploy / ship to others, you will have to also use the above-described workflow, at least to test the project - as long as your final layout is not exactly the same as your WB project (but probably even if they are the same).

Leonid, I hope you have some time to spare to weigh in on this. With some strong backing from professional mma users on board, I'll make a push to SE to see what can be done about it.
–
rm -rf♦Nov 14 '12 at 16:33

@rm-rf I've added an answer. Hope this will help! Let me know if you'd like to see something there which I missed, and I will edit it.
–
Leonid ShifrinNov 14 '12 at 17:40

@LeonidShifrin This is really helpful answer. You are too polite, documentation sucks when one want to learn how to set up a proper package, scalable and in modular manner. Relations between Begin Begin Package Contexts InputFile etc are described vaguely and splitted between many ref - tutorials sub notebooks which are usually not linked together nicely.
–
KubaFeb 21 at 9:23

@LeonidShifrin When you find some time, pleas take a look at my answer here if it is correct.
–
KubaFeb 21 at 9:40

@Kuba I think your answer is right, and I upvoted it. However, as for the docs, I think they never meant to have <<dir - this was just a bad wording they chose. They meant to say "if the project turns out to be a dir", or something along those lines.
–
Leonid ShifrinFeb 21 at 13:03

Mathematica is a registered trademark of Wolfram Research, Inc. While the mark is used herein with the limited permission of Wolfram Research, Stack Exchange and this site disclaim all affiliation therewith.