MATLAB Answers

Why do deep paths in \usepackage cause texmex to crash (segmentation violation)?

41 views (last 30 days)
Joseph
Joseph on 31 Oct 2012
Edited: Julian Williams on 22 Feb 2019
Short version:
I call texmex.mexw64 on a tex file, like this:
[dvi,loginfo,err] = texmex(tstr, texpath, 1, logical(0));
The string tstr is essentially the entire tex file. In it, I specify what packages to use and the path to them ('\usepackage{...}'). If that path is too deep, matlab crashes. Why, and is there a workaround (other than moving my files around, creating junctions, etc.)? [Actually, the problem appears to be the length of the pathname/filename, not the path depth; see update at bottom.]
Long version:
Matlab provides a mex file called texmex.mexw64 (in matlabroot/toolbox/matlab/graphics/private) for generating LaTeX (for plot titles, etc.); in particular, it generates dvi output from tex inputs. Normally, it's invoked by tex.m (one directory up), but I'd like to use packages that aren't included in tex.m. (In fact, I first generated this error when running a modified version of tex.m, but I can regenerate it more simply by invoking texmex directly from the command line.) The original c code that generated texmex.mexw64 isn't available, so I can't hunt down the bug any further.
Here's a minimal working/non-working example:
clear; clc; close all;
% get access to private texmex files
%%%This is *not* the problem!
privateDir = [matlabroot,'\toolbox\matlab\graphics\private'];
texmexPrvt = get_private_fcn(privateDir,'texmex');
mlinitexPrvt = get_private_fcn(privateDir,'mlinitex');
% set tex path
%%%This is also not the problem, just part of the MWE.
texpath{1} = fullfile(matlabroot,'sys','fonts','type1','cm',filesep);
texpath{end+1} = fullfile(matlabroot,'sys','tex',filesep);
texpath{end+1} = fullfile(matlabroot,'sys','tex','latex','base',filesep);
texpath{end+1} = fullfile(matlabroot,'sys','tex','tfm',filesep);
[c,maxsize,endian] = computer;
if strncmp(endian,'B',1)
texpath{end+1} =...
fullfile(matlabroot,'sys','tex','format','bigendian',filesep);
else
texpath{end+1} =...
fullfile(matlabroot,'sys','tex','format','smallendian',filesep);
end
setappdata(0,'TeXPath',texpath);
% test
%%%this version works
strint = '%&latex \nofiles \documentclass{mwarticle} ';
strpkge = '\usepackage{C:/stys/two/three/four/five/six/foo} ';
strbgn = '\begin{document}\setbox0=\hbox{$\foofoo$}';
strend = '\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0} \end{document}';
sstr = [strint,strpkge,strbgn,strend];
[dvi,loginfo,err]=texmexPrvt(sstr, texpath, 1, logical(0));
pause();
%%%this version does not work
strpkge = '\usepackage{C:/stys/two/three/four/five/six/seven/foo} ';
sstr = [strint,strpkge,strbgn,strend];
[dvi,loginfo,err]=texmexPrvt(sstr, texpath, 1, logical(0));
The sty file foo.sty lives in both directories, C:/stys/two/three/four/five/six/ and C:/stys/two/three/four/five/six/seven, but somehow the latter is one too deep (apparently) for matlab to find it. (The style file itself is not the problem; it consists of a single macro, \newcommand{\foofoo}{\bf s}.) Running the last three lines above yields a segmentation violation. I doubt the register values at crash time or etc. will help. I also suspect that this directory issue is one of several in texmex. What I'd really like is to get the original c file, but short of that I'd like to know why this is happening and how to work around it. I don't want to move my style files around to different directories.
Thanks.
[UPDATE] In fact, it appears that the problem isn't the path depth, but the length of the pathname/filename. I don't want to keep crashing matlab to find out, but it looks like the limit is 32 characters.

  6 Comments

Show 3 older comments
Joseph
Joseph on 1 Nov 2012
After quite a bit of headache, I've decided that trying to coax matlab's texmex into behaving properly isn't worth it. Instead I've edited the file tex.m to use the latex that's already in the Windows path, i.e. from my copy of the MiKTeX distribution. In case anyone else wants some similar functionality (giving matlab access to one's own style files, to other packages that are available through MiKTeX, etc. etc.), I'm posting my edited version here. It lives in some directory that has higher priority in the path than matlabroot/toolbox/matlab/graphics/, which is where the original tex.m lives. Everything I've edited has been clearly marked. It's possible that this breaks something else---I haven't thoroughly checked---but it works for, e.g., this:
h = text('string','$\overset{*}{X}$','interpreter','latex','pos',[0.2 0.5],'Fontsize',30);
Note that I've also put a copy of mwarticle.cls from matlabroot\sys\tex\ into the directory where the tex files are to be written (for me, C:\Documents and Settings\username\My Documents\#texs\matlab). You can see where I placed the usepackage lines and therefore where to add your own.
[UPDATE: Daniel has alerted me to the fact that this function, being matlab's, is copyrighted. I've pared it down to just my edits and the surrounding code (for context).]
function [dviout,errout,auxout] = tex(str,varargin)
%
% ...omitting help-section commenting...
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fprintf('USING THE MODIFIED tex.m -- jgm\n');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%...omitting matlab's code...
%
if isempty(err)
[tstr] = localDecorateInputString(str,format,width,fragment);
%%%%%%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%
% [dvi,loginfo,err] = localCallTeXParser(tstr,doinitex,verbose,dofileio);
% write preamble to .tex file
cstr = '\nofiles \documentclass{mwarticle} ';
cstr = [cstr,'\newcommand{\stydir}{../stys} '];
cstr = [cstr,'\usepackage{amsmath,amssymb,amsfonts,'];
cstr = [cstr,'graphicx,color,amsthm,versions,nameref,'];
cstr = [cstr,'\stydir/jgmstd,\stydir/rbmish,\stydir/optimal} '];
cstr = [cstr,tstr];
% switch to your own tex/matlab directory, where you keep mwarticle.cls
texdir = 'C:\Documents and Settings\username\My Documents\#texs\matlab';
olddir = cd(texdir);
texID = fopen('matTeX.tex','w');
fwrite(texID,cstr);
fclose(texID);
% run MiKTeX's latex (it's on the path)
!latex -quiet -src-specials -interaction=nonstopmode matTeX.tex
% get the contents of the dvi file
FID = fopen('matTeX.dvi','r');
dvidbl = fread(FID);
fclose(FID);
dvi = uint8(dvidbl);
err = '';
loginfo = {};
% return to the working dir
cd(olddir)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
%
%...omitting matlab's code...
%
function [tstr] = localDecorateInputString(str,format,width,fragment)
%
%...omitting matlab's code...
%
if strcmp(format(3:end),'latex')
%%%%%%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%
% standardhead =' \nofiles \documentclass{mwarticle} \begin{document}';
standardhead = ' \begin{document}';
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
standardtail = ' \end{document}';
else
standardhead = ' \relax \nopagenumbers \noindent';
standardtail = ' \bye';
end
if isempty(width)
%
%...omitting matlab's code...
%
if fragment
%%%%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%
% tstr = [ format standardhead '\setbox0=\hbox{' tstr ...
% '}\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0}' ...
% standardtail];
tstr = [standardhead '\setbox0=\hbox{' tstr ...
'}\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0}' ...
standardtail];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
else
% For now, let input string define format, this is used when
% generating format files (i.e. plain.fmt)
% tstr = [ format ' ' tstr ];
end
else
if fragment
%%%%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%
% tstr = [ format standardhead ' \hsize=' width ' \setbox0=\hbox{' str ...
% '}\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0}' ...
% standardtail];
tstr = [standardhead ' \hsize=' width ' \setbox0=\hbox{' str ...
'}\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0}' ...
standardtail];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
else
%%%%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%
% tstr = [ format ' ' tstr ];
tstr = [ ' ' tstr ];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
end
end
%-------------------------------------------------------------------------%
%-------------------------------------------------------------------------%
function [dvi,loginfo,err] =...
localCallTeXParser(tstr,doinitex,verbose,dofileio)
%%%You no longer need to use this function. Just in case, though, you've
%%%left in the workaround to get to the private mex files. (JGM)
dvi = [];
loginfo = [];
%err = [];
[texpath,err] = localGetTeXPath;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
privateDir = [matlabroot,'\toolbox\matlab\graphics\private'];
texmexPrvt = get_private_fcn(privateDir,'texmex');
mlinitexPrvt = get_private_fcn(privateDir,'mlinitex');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
try
if isempty(err)
% Send output to files
if dofileio
if doinitex
%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%
mlinitexPrvt(tstr, texpath, verbose, dofileio);
else
texmexPrvt(tstr, texpath, verbose, dofileio);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
% Send output to return variables
else
if doinitex
%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%
[dvi,loginfo,err] =...
mlinitexPrvt(tstr, texpath, verbose, dofileio);
else
[dvi,loginfo,err] =...
texmexPrvt(tstr, texpath, verbose, dofileio);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
end
end
%
%...omitting matlab's code...
%
function localLoadType1FontsOnWindows(names,paths)
%
%...omitting matlab's code...
%
while n<length(names)
%
%...omitting matlab's code...
%
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
privateDir = [matlabroot,'\toolbox\matlab\graphics\private'];
loadfontsPrvt = get_private_fcn(privateDir,'loadfonts');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Pass to mexfile for GDI loading
loadfontsPrvt(path_2_pfm_pfb_files);
end
%
%...omitting matlab's code...
%
Chibuzo Nnonyelu
Chibuzo Nnonyelu on 18 Dec 2018
The tex.m file I saw in the given file path contains only comments. Where else can find this file with matlab codes?
Walter Roberson
Walter Roberson on 18 Dec 2018
Note the 2012 date on the original question . The handling of tex has changed twice since then. As far as I know in current releases there is no way to customise tex or latex for plotting use.
However there is a way to customise tex and latex for use with publish() I believe .

Sign in to comment.

Accepted Answer

Daniel Shub
Daniel Shub on 2 Nov 2012
I can recreate your problem on R2011a Linux. I modified your MWE to be
texpath{end+1} = 'C:/stys/two/three/four/five/six/seven/';
strpkge = '\usepackage{foo} ';
and it works. I would think that the 'addpath' pv of tex.m would do this automatically, but I haven't tested it. I am not sure what your actual use case is but I cannot easily think of a use case where you want to give the path in \usepackage instead of adding it to the search path. That said, I don't know why it crashes. I was hoping to be able to replace the "tex binary" that texmex relies on, but I wasn't able to find it.

  1 Comment

Joseph
Joseph on 2 Nov 2012
Yes, that works! As you say, it still doesn't say why matlab's latex can't use long path names.... But some mysteries are better left unsolved: I recommend to any matlab users seeking to accomplish what I was---using lots of non-default latex style files within matlab---not to use this approach at all, but to modify tex.m along the lines of my (long) comment above. Adding each directory to matlab's texpath (my original approach) will generally be far more work than relying on the directory structure of one's own latex distribution (MiKTeX, etc.).
If you don't like modifying matlab's internal files, though, or if you don't have another dstrb of latex on your machine, take the original approach, w/Daniel's v. helpful solution.

Sign in to comment.

More Answers (1)

Julian Williams
Julian Williams on 22 Feb 2019
Edited: Julian Williams on 22 Feb 2019
I have given up trying to add packages to the matlab latex installation.
My suggestion for 2D plots is to do the following:
  1. Design the picture/plot/infographic as you needed and put some place holders in as labels/axes/legends.
  2. Use the "matlab2tikz" package from the Matlab Central repository.
  3. Save the plots into Tikz as a seperate tex file, then edit the labels as needed using the packages you need, you can even create a macro to automatically edit the text the way you want it.
  4. Then use an "input" from the latex source to add the plot. It can slow the compilation process, but you have more control on the output.
I tried several times (in 2016a) to edit the underlying latex repository (for instance by copying packages into the location) in Matlab and have only ever managed to do nothing or irrepairably break my matlab installation. My guess is that Mathworks realized this was a bit dangerous, so now the entire Latex compiler assemblage is in a binary, so you cannot manually adjust it.

  0 Comments

Sign in to comment.

Sign in to answer this question.


Translated by