I have a variable:
set(${PROJECT_NAME}_EXTERNAL_LIBRARIES
${PocoNetExternal_LIBRARIES}
)
Which comes from:
set(EXTERNAL_NAME PocoNetExternal)
set(${EXTERNAL_NAME}_LIBRARIES
${PROJECT_BINARY_DIR}/${EXTERNAL_NAME}/Foundation/${CMAKE_SHARED_LIBRARY_PREFIX}PocoFoundation${POCO_build_postfix}${CMAKE_STATIC_LIBRARY_SUFFIX}
${PROJECT_BINARY_DIR}/${EXTERNAL_NAME}/Util/${CMAKE_SHARED_LIBRARY_PREFIX}PocoUtil${POCO_build_postfix}${CMAKE_STATIC_LIBRARY_SUFFIX}
${PROJECT_BINARY_DIR}/${EXTERNAL_NAME}/Net/${CMAKE_SHARED_LIBRARY_PREFIX}PocoNet${POCO_build_postfix}${CMAKE_STATIC_LIBRARY_SUFFIX}
)
Because of the issue discussed in This Question, I need all of these paths to be relative.
I have tried this:
function(makeLibPathsAbsolute)
set(temp ${${PROJECT_NAME}_EXTERNAL_LIBRARIES}) #rename list
set(external_libraries_rel) #make empty list
list(LENGTH temp len1) #len1 is length of temp list
math(EXPR len2 "${len1} - 1") #len2 is len1 - 1
foreach(val RANGE ${len2}) #for val = 0 to len2
list(GET temp ${val} relPath) #relPath becomes the {val} entry of temp
get_filename_component(absPath ${relPath} ABSOLUTE) #make relPath Absolute and call it absPath
list(APPEND external_libraries_rel ${absPath}) #Append this to the external_libraries_rel list
endforeach()
endfunction()
But when I use target_link_libraries(${name} ${external_libraries_rel}) I get an Undefined Reference Error for all of the functions related to the library I am trying to link. Indicating that the library has not actually been linked.
Is my makeLibPathsAbsolute() function correct?
By default, all variables set in the function are not visible outside. (In other words, variable's definition is scoped to the function).
For make variable visible for the function's caller, use PARENT_SCOPE option of the set() command.
E.g. you may "publish" external_libraries_rel list by appending this line to the end of the function:
set(external_libraries_rel ${external_libraries_rel} PARENT_SCOPE)
Related
Been having fun with a homebrew doco system in Lua. e.g.
fun("abs","return abs value", function (x,y)
return math.abs(x,y) end)
I'm stuck on one detail. I want to make "abs" a local function . But I do not know how to do that programmatically.
Of course, I could write to a field in some Lib object and call it Lib.abs(x,y) and I think that is what I'm going to have to do. BUT can any smart Lua person tell me how to not do that?
I don't think you have much of a choice, as while you can assign a value to a local variable (using debug.setlocal function), it's assigned by index, not by name, so there has to exist a local variable already with that index.
I don't see anything wrong with your suggestion to store the function in a table field.
What I would do is, I'd write(or even override) _G, run your function/program, and then restore it.
function callSandboxed(newGlobals, func)
local oldGlobals = {} --make a new table to store the values to be writen (to make sure we don't lose any values)
for i,_ in pairs(newGlobals) do
table.insert(oldGlobals, _G[i]) --Store the old values
_G[i] = newGlobals[i] --Write the new ones
end
func() --Call your function/program with the new globals
for i,v in pairs(oldGlobals) do
_G[i] = v --Restore everything
end
end
In this case, what you want to do is:
--Paste the callSandboxed function
callSandboxed({abs=math.abs},function()print(abs(-1))end) --Prints 1
If you want to remove ALL the old values from _G (not only the ones you want to replace), then you could use this:
function betterCallSandboxed(newGlobals, func) --There's no point deep copying now, we will replace the whole table
local oldGlobals = _G --Make a new table to store the values to be writen (to make sure we don't lose any values)
_G = newGlobals --Replace it with the new one
func() --Call your function/program with the new globals
_G = oldGlobals
end
Now if inside func, print and math(etc) are nil.
The Pandoc documentation says that cross references can be made to section headers in a number of ways. For example, you can create your own ID and reference that ID. For example:
# This is my header {#header}
Will create an ID with value '#header' that can be refenced in the text, as such:
[Link to header](#header)
Which will display the text 'Link to header' with a link to the header.
I couldn't find anywhere how to make the text of the link be the section number when compiled as a LaTeX document.
For example, if my header is compiled to '1.2.3 Section Header', I want my cross-reference to text to display as '1.2.3'.
This can be achieved by defining the ID as done previously. eg:
# This is my header {#header}
Then in the text, the cross reference can be written as:
\ref{header}
When this compiles to LaTeX, the cross-reference text will be the section number of the referenced heading.
You can use the pandoc-secnos filter, which is part of the pandoc-xnos filter suite.
The header
# This is my header {#sec:header}
is referenced using #sec:header. Alternatively, you can reference
# This is my header
using #sec:this-is-my-header.
Markdown documents coded in this way can be processed by adding --filter pandoc-secnos to the pandoc call. The --number-sections option should be used as well. The output uses LaTeX's native commands (i.e., \label and \ref or \cref).
The benefit to this approach is that output in other formats (html, epub, docx, ...) is also possible.
A general solution which works with all supported output formats can be build by leveraging pandoc Lua filters: The function pandoc.utils.hierarchicalize can be used to get the document hierarchy. We can use this to associate section IDs with section numbers, which can later be used to add these numbers to links with no link description (e.g., [](#myheader)).
local hierarchicalize = (require 'pandoc.utils').hierarchicalize
local section_numbers = {}
function populate_section_numbers (doc)
function populate (elements)
for _, el in pairs(elements) do
if el.t == 'Sec' then
section_numbers['#' .. el.attr.identifier] = table.concat(el.numbering, '.')
populate(el.contents)
end
end
end
populate(hierarchicalize(doc.blocks))
end
function resolve_section_ref (link)
if #link.content > 0 or link.target:sub(1, 1) ~= '#' then
return nil
end
local section_number = pandoc.Str(section_numbers[link.target])
return pandoc.Link({section_number}, link.target, link.title, link.attr)
end
return {
{Pandoc = populate_section_numbers},
{Link = resolve_section_ref}
}
The above should be saved to a file and then passed to pandoc via the --lua-filter option.
Example
Using the example from the question
# This is my header {#header}
## Some subsection
See section [](#header), especially [](#some-subsection)
Using the above filter, the last line will render as "See section 1, especially 1.1".
Don't forget to call pandoc with option --number-sections, or headers will not be numbered.
Since pandoc version 2.8 the function pandoc.utils.hierarchicalize has been replaced with make_sections. Here is an updated version of the #tarleb's answer which works with newer ´pandoc´ versions.
local make_sections = (require 'pandoc.utils').make_sections
local section_numbers = {}
function populate_section_numbers (doc)
function populate (elements)
for _, el in pairs(elements) do
if el.t == 'Div' and el.attributes.number then
section_numbers['#' .. el.attr.identifier] = el.attributes.number
populate(el.content)
end
end
end
populate(make_sections(true, nil, doc.blocks))
end
function resolve_section_ref (link)
if #link.content > 0 or link.target:sub(1, 1) ~= '#' then
return nil
end
local section_number = pandoc.Str(section_numbers[link.target])
return pandoc.Link({section_number}, link.target, link.title, link.attr)
end
return {
{Pandoc = populate_section_numbers},
{Link = resolve_section_ref}
}
Let's say I'm working with a lua library I installed using luarocks, and I want to see the definition of a function from that library. In ipython in could use
??function_name
to see the definition in the terminal, in matlab I could use
which function_name
then use my editor to look at the path returned by which. How could I do something similar to find the function definition for a lua library?
In 'plain' Lua/JIT, you can say debug.getinfo( func ) and will get a table containing (among others) the fields short_src, source and linedefined.
For Lua functions, short_src will be the filename or stdin if it was defined in the REPL. (source has a slightly different format, filenames are prefixed with an #, a = prefix is used for C functions or stuff defined interactively, and for loaded functions, it will be the actual string that was loaded.)
You can pack that up in a function like
function sourceof( f )
local info = debug.getinfo( f, "S" )
return info.short_src, info.linedefined
end
or maybe even start an editor and point it there, e.g. (for vim)
function viewsource( f )
-- get info & check it's actually from a file
local info = debug.getinfo( f, "S" )
local src, line = info.source, info.linedefined
if src == "=[C]" then return nil, "Is a C function." end
local path = src:match "^#(.*)$"
if path then
-- start vim (or an other editor if you adapt the format string)
return os.execute( ("vim -fR %q +%d"):format( path, line ) )
end
return nil, "Was defined at run time."
end
And just for fun, here's yet another version that returns the code if it can find it somewhere. (This will also work for functions that have been generated at run time, e.g. by calling load, and where no source file exists. You could also work in the other direction by dumping the loaded snippet into a temp file and opening that…)
-- helper to extract the source block defining the function
local function funclines( str, line1, lineN, filename )
-- if linedefined / lastlinedefined are 0, this is the main chunk's function
if line1 == 0 and lineN == 0 then
filename = filename and filename.." (main chunk)"
or "(chunk defined at runtime)"
return "-- "..filename.."\n"..str
end
-- add line info to file name or use placeholder
filename = filename and filename..":"..line1 or "(defined at runtime)"
-- get the source block
local phase, skip, grab = 1, line1-1, lineN-(line1-1)
local ostart, oend -- these will be the start/end offsets
if skip == 0 then phase, ostart = 2, 0 end -- starts at first line
for pos in str:gmatch "\n()" do
if phase == 1 then -- find offset of linedefined
skip = skip - 1 ; if skip == 0 then ostart, phase = pos, 2 end
else -- phase == 2, find offset of lastlinedefined+1
grab = grab - 1 ; if grab == 0 then oend = pos-2 ; break end
end
end
return "-- "..filename.."\n"..str:sub( ostart, oend )
end
function dumpsource( f )
-- get info & line numbers
local info = debug.getinfo( f, "S" )
local src, line, lastline = info.source, info.linedefined, info.lastlinedefined
-- can't do anything for a C function
if src == "=[C]" then return nil, "Is a C function." end
if src == "=stdin" then return nil, "Was defined interactively." end
-- for files, fetch the definition
local path = src:match "^#(.*)$"
if path then
local f = io.open( path )
local code = f:read '*a'
f:close( )
return funclines( code, line, lastline, path )
end
-- otherwise `load`ed, so `source`/`src` _is_ the source
return funclines( src, line, lastline )
end
A closing remark: If you paste code into a Lua/JIT REPL, locals disappear between definitions, because every line (or minimal complete group of lines) is its own chunk. The common fix (that you probably know) is to wrap everything into a block as do*paste*end, but an alternative is to load[[*paste*]]() (possibly with more =s like [===[ and ]===].) If you paste this way, the above dumpsource (or any other function using debug.getinfo) will then be able to get the source of the function(s). This also means that if you defined a nice function but it's gone from the history and the scroll buffer, you can recover it in this way (if you defined it by loading and not directly feeding the interpreter). Saving the source in a file will then also be possible without copy-pasting and not require editing out the >> prompts.
I would like to have a dynamic variable name and want to be able to eval and get the value of it and was wondering if this was available. Example on how I want to use it.
audio.play(eval("readAloudPage"..page_num)))
If the value of a global variable is sought, then try _G["readAloudPage"..page_num].
Or define
function eval(name)
return _G[name]
end
Dynamic variable names must be table fields: the globals table which is named _G, or your own table if you don't want to use globals (usually the case). Example:
local yourDynVars = {}
yourDynVars["readAloudPage"..page_num] = ...
audio.play(yourDynVars["readAloudPage"..page_num])
print( yourDynVars.readAloudPage2 ) -- not dynamic; prints nil unless page_num was 2, above
If you replace yourDynVars table by _G the only difference is that in the last line you can access the var directly:
_G["readAloudPage"..page_num] = ...
audio.play(_G["readAloudPage"..page_num])
print( readAloudPage2 ) -- not dynamic; prints nil unless page_num was 2, above
Lua's closest equivalent to eval(code) would be loadstring(code)().
Notice loadstring(code) does not execute the code, it dynamically creates a function with it. Use loadstring(code)() to create and run it.
The closest you can get is lhf's solution to use _G["readAloudPage"..page_num].
Lua provides loadstring function to convert strings to executable functions, but this function is disabled in Corona SDK (and can only be used/accessed in debug environment).
It is my understanding that in Lua 5.2 that environments are stored in upvalues named _ENV. This has made it really confusing for me to modify the environment of a chunk before running it, but after loading it.
I would like to load a file with some functions and use the chunk to inject those functions into various environments. Example:
chunk = loadfile( "file" )
-- Inject chunk's definitions
chunk._ENV = someTable -- imaginary syntax
chunk( )
chunk._ENV = someOtherTable
chunk( )
Is this possible from within Lua? The only examples I can find of modifying this upvalue are with the C api (another example from C api), but I am trying to do this from within Lua. Is this possible?
Edit: I'm unsure of accepting answers using the debug library. The docs state that the functions may be slow. I'm doing this for efficiency so that entire chunks don't have to be parsed from strings (or a file, even worse) just to inject variable definitions into various environments.
Edit: Looks like this is impossible: Recreating setfenv() in Lua 5.2
Edit: I suppose the best way for me to do this is to bind a C function that can modify the environment. Though this is a much more annoying way of going about it.
Edit: I believe a more natural way to do this would be to load all chunks into separate environments. These can be "inherited" by any other environment by setting a metatable that refers to a global copy of a chunk. This does not require any upvalue modification post-load, but still allows for multiple environments with those function definitions.
The simplest way to allow a chunk to be run in different environments is to make this explicit and have it receive an environment. Adding this line at the top of the chunk achieves this:
_ENV=...
Now you can call chunk(env1) and later chunk(env2) at your pleasure.
There, no debug magic with upvalues.
Although it will be clear if your chunk contains that line, you can add it at load time, by writing a suitable reader function that first sends that line and then the contents of the file.
I do not understand why you want to avoid using the debug library, while you are happy to use a C function (neither is possible in a sandbox.)
It can be done using debug.upvaluejoin:
function newEnvForChunk(chunk, index)
local newEnv = {}
local function source() return newEnv end
debug.upvaluejoin(chunk, 1, source, 1)
if index then setmetatable(newEnv, {__index=index}) end
return newEnv
end
Now load any chunk like this:
local myChunk = load "print(x)"
It will initially inherit the enclosing _ENV. Now give it a new one:
local newEnv = newEnvForChunk(myChunk, _ENV)
and insert a value for 'x':
newEnv.x = 99
Now when you run the chunk, it should see the value for x:
myChunk()
=> 99
If you don't want to modify your chunk (per LHF's great answer) here are two alternatives:
Set up a blank environment, then dynamically change its environment to yours
function compile(code)
local meta = {}
local env = setmetatable({},meta)
return {meta=meta, f=load('return '..code, nil, nil, env)}
end
function eval(block, scope)
block.meta.__index=scope
return block.f()
end
local block = compile('a + b * c')
print(eval(block, {a=1, b=2, c=3})) --> 7
print(eval(block, {a=2, b=3, c=4})) --> 14
Set up a blank environment, and re-set its values with your own each time
function compile(code)
local env = {}
return {env=env, f=load('return '..code, nil, nil, env)}
end
function eval(block, scope)
for k,_ in pairs(block.env) do block.env[k]=nil end
for k,v in pairs(scope) do block.env[k]=v end
return block.f()
end
local block = compile('a + b * c')
print(eval(block, {a=1, b=2, c=3})) --> 7
print(eval(block, {a=2, b=3, c=4})) --> 14
Note that if micro-optimizations matter, the first option is about 2✕ as slow as the _ENV=... answer, while the second options is about 8–9✕ as slow.