# How can I include functions from a package into a CDF file?

I am building an application which I would like to deploy as a CDF file, and I am struggling to make the CDF exports work correctly with functions pulled from a .m package file. What are good/best practices for handling such situations?

In particular, the code below encapsulates (at least partly) some of my difficulties. Make a package in the file TestPackage.m with the definitions

BeginPackage["TestPackage"]
f::usage="f[x] returns a plot.";
Begin["Private"]
f[x_]:=Plot[Sin[x y],{y,0,2 Pi},PlotRange->{-1,1},ImageSize->500]
End[]
EndPackage[]


and include it in the same directory as the following code in a notebook.

Needs["TestPackage", NotebookDirectory[] <> "TestPackage.m"]
DynamicModule[
{a = 1},
Column[{
Slider[Dynamic[a]],
Dynamic[f[a]]
}]
, Initialization :> (
Needs["TestPackage", NotebookDirectory[] <> "TestPackage.m"]
)
]
Export[NotebookDirectory[] <> "output.cdf", EvaluationNotebook[]]


The DynamicModule correctly produces the desired output. If I close the notebook and reopen it, the plot renders correctly (which is not the case if the Initialization Needs is omitted). If I open the resulting output.cdf using Mathematica, the plot also renders correctly.

However, if I open output.cdf using the Wolfram CDF Player 10.1, the only thing that shows underneath the Slider is TestPackagef[1.] (or whatever the value of a is).

I also tried naively spewing the contents of the package onto the initialization rule, along the lines of

Initialization :> (
ImportString[Import[NotebookDirectory[] <> "TestPackage.m", "Text"],
"NB"]
)


but it produces exactly the same behaviour. Presumably there exists a way to do this, but this simply puts the above code into the CDF, which the player then refuses to execute.

How can I make this plot render correctly in the exported CDF version?

• I'd have a look at SaveDefinitions option (just a guess. By far not an expert on this). – Leonid Shifrin Jun 23 '15 at 21:23
• The problem is that FreePlayer has I/O restrictions. You can inject with e.g. With your package in text form to Initialization and Get+StringToStream if you don't trust SaveDefinitions. You should be able to incorporate password protected encoded packages with this method. Not perfect but nice enough for free player. – Kuba Jun 23 '15 at 21:29
• closely related: How to create protected single-file stand-alone CDF applications – Kuba Jun 23 '15 at 21:30
• @Leonid You're right, SaveDefinitions does in fact fix this example. Which means that this doesn't capture whatever is wrong with my bigger code. Back to the drawing board on that, then. Still, if there's a way to replicate the package's definitions in the Initialization stage it should help there. – Emilio Pisanty Jun 23 '15 at 21:42
• @episanty don't worry it's not the point. :) I like this question a lot because it should be stressed out by tutorials of Mathematica how to work with their products. Or rather how to connect different functionalities like Packages Manipulate, Free Player, PlayerPro in context of code security, deployment of standalone files etc etc. So thank's for asking. – Kuba Jun 27 '15 at 13:03

There are some doubts about using SaveDefinitions (1), (2), so let's implement a brute force approach which may be later used automatically.

### Outline

Needs @ yourPackage  (*a*)

CDFDeploy @ With[
{ source = Import[packagePath] (*b*) }
, DynamicModule[
{ ... }
, ...
, Initialization :> ( Get @ StringToStream @ source )
]

• (a). You have to call you package before creating DynamicModule because you need all static content (not held/dynamic) in the body of DM to be parsed and evaluated properly.

And all dynamic/held names to be "typeset" with proper context name. And they will be found thanks to $ContextPath modified by BeginPackage and friends. (3) • (b). We have to use With to inject source into DynamicModule's Initialization because Initialization is set with RuleDelayed which is HoldRest. • For more complex/time consuming packages you may want to change SynchronousInitialization->False and monitor the state of initialization analogously to: Working with DynamicModule: Tracking the progress of Initialization ### Execution First code block is only to create a test package: content = " BeginPackage[\"TestPackage\"] f::usage=\"f[x] returns a plot.\"; Begin[\"Private\"] f[x_]:=Plot[Sin[x y],{y,0,2 Pi},PlotRange->{-1,1},ImageSize->500] End[] EndPackage[]"; path = FileNameJoin[{$TemporaryDirectory, "package.m"}];
pathEnc = FileNameJoin[{$TemporaryDirectory, "package.enc"}]; pathCDF = FileNameJoin[{$TemporaryDirectory, "CDF.cdf"}]

Export[path, content, "Text"];


Now the actual code:

Encode[path, pathEnc];  (*c*)
encodedpackage = Import[pathEnc, "Text"];

Get @ pathEnc (*a*)

CDFDeploy[ pathCDF, #, Method -> "Standalone", "Target" -> "CDFPlayer"
] & @
With[ { source = encodedpackage (*b*) }
, DynamicModule[{x = 1}
, Column[{
Dynamic[{x, f[x]}],
Button["x++", x++],
Dynamic @ \$ContextPath
}]
, Initialization :> Module[{stream}
, stream = StringToStream @ source
; Get @ stream
; Close @ stream
]
]
]


c. we are Encoding source, it is then obscure for others and already compressed so why not. You can even incorporate password protection with this method: (4). It won't be fully secure, as pointed in comments here: (5).

You can now go to the CDF and test in the FreePlayer:

SystemOpen @ DirectoryName @ pathCDF


(1) The dangers of SaveDefinitions

(2) Not FullDefinition for Save. MachineID not Protected?

(3) load a Mathematica package inside a DynamicModule

• +1 (a while ago). This is a solid solution that works nicely for probably the vast majority of deployments. It doesn't however, cover the case where one wants to employ "lazy loading" as implemented in a package framework. For example, there may be a corner interface interaction that requires a function whose definition that you don't necessarily want to load on initialization (into the runtime) but only when the user reaches that corner. The way this would be normally be implemented (with DeclarePackage` working with file/folder layout) doesn't seem reproducible within a CDF. – Ronald Monson Jan 21 at 23:06