Help Bites



  • @error That's what it looks like. I suspect it's the new version of Wordpress, since that is the major difference between the environment where it works and where it doesn't, but I haven't found confirmation that that's what it is, or how to work around it.


  • Discourse touched me in a no-no place

    @hungrier said in Help Bites:

    Now, no matter what I put in the action attribute on the template that has that form, it always points to https://root.of.site.com/.

    Just checking: is that address in the DOM, and was it in the document that was actually delivered? We're not looking for some after-the-load Javascript changing things under your feet? WP's bad enough without adding in that sort of insanity as well.



  • @dkf I had checked the response in the network panel of devtools, and from the look of it the page was already being served with the incorrect action URL, without any client side js nonsense altering it.


  • Considered Harmful

    @hungrier maybe a new crosscutter? Does WP have a notion of perhaps security? In Spring, a smell like this would have me looking there.

    Or, equally likely, you are supplying an empty path.



  • @topspin said in Help Bites:

    @PleegWat that's it!

    root@LGwebOSTV:/usr/bin# pgrep com.webos.app.h
    1851
    root@LGwebOSTV:/usr/bin# pgrep com.webos.app.ho
    root@LGwebOSTV:/usr/bin
    

    That's ... pretty stupid.
    Thanks!

    Ha! I see the solution: their o is not a common ASCII o, but some weird foreign version, perhaps cyrillic?



  • @Gribnit If I'm right about it being caused by updated Wordpress, the reason is probably security related. I do know I'm not supplying an empty path, but Wordpress may be taking what I put and emptying it all by its own decision.


  • Discourse touched me in a no-no place

    @hungrier said in Help Bites:

    If I'm right about it being caused by updated Wordpress, the reason is probably security related.

    It's wordpress, so it could just be a fuck-up caused by a change of expectations. Unfortunately, you'll probably have to seek help elsewhere (such as the Wordpress forums) because many of us simply haven't the expertise to ask the correct questions to narrow down where the problem may be.


  • 🚽 Regular

    The one person I can think to name drop, @Arantor, hasn't been around. :/



  • Is there any way of testing stuff on MacOS without having to buy/borrow a Mac? I have to debug building and running some stuff (C/C++, so native code) on a Mac, because there are some people who are Apple-encumbered and don't have any great alternatives (and dealing with them individually is a pain).

    IIRC Microsoft provides pre-built Windows images for this kind of stuff, but as far as I can tell, Apple doesn't.


  • Discourse touched me in a no-no place

    @cvi Interactive or batch mode? For batch mode testing, you can use a macOS image in Github Actions; it's mostly very similar to other Unixes at that level.

    Interactive GUI stuff really requires having the hardware and the OS and the rest.



  • @dkf Batch mode might be sufficient -- just knowing that things build would be a good first step. I'll take a look at Github actions (not using that ATM, but it's come up a few times already anyway). Thanks.

    I know that the code can be built and ran under MacOS. Others have done so already, but they had to fix up some things in the build config, and a library was missing some MacOS specific things. Unfortunately, I never got hold of the changes (and without a testing environment, I wouldn't be able to maintain them anyway).


  • Considered Harmful

    @hungrier said in Help Bites:

    @Gribnit If I'm right about it being caused by updated Wordpress, the reason is probably security related. I do know I'm not supplying an empty path, but Wordpress may be taking what I put and emptying it all by its own decision.

    Hail Mary, my guess is it sees separators and tosses it, because now it wants the components as discrete array members and/or in a variable-arity call.



  • There's a city-building game that I like to play. When the player creates a road in the city, the game assigns a random name to the road. Sometimes it reuses a name for a completely different road in a different part of the city, which I find annoying. (The fact that it sometimes randomly renames roads, or parts of them, when the player makes the slightest change is even more annoying, but that's irrelevant to this question.) So I would like to get a list of all the named roads and look for duplicates.

    I haven't tried reverse engineering the game's own data format, but there's a mod that exports data that an external program can use to create a map of the city. It turns out this data is (compressed) XML, so extracting the road name info from it is trivial. Figuring out whether the same name is used for multiple roads, not so much.

    The data consists of nodes and segments that connect those nodes. Being a road is a property of a node (the Node element has a type attribute of "Road") and the name is a property of the Seg element (CustomName attribute). The segment also has start and end node attributes (sn and en, respectively), which contain the id of the associated Nodes. So, we can (tentatively) define a road as a sequence of Seg elements in which the sn attribute is equal to the en attribute of the previous Seg. (I'm not sure whether the resulting graph is completely directed. It may be possible that in some cases it may be the en attribute of one Seg that may be equal to the en of the previous.)

    (There are also Nodes of other types, but those are irrelevant to the question; I've already extracted the relevant road elements. AFAICT so far, the Node elements themselves are of interest only for the purpose of which Segs are part of "Road" networks.)

    So, what I essentially want to do is go through pair-wise the list of Segs with the same name comparing the sn and en attributes, finding sets that form a continuous path between nodes. Is there an algorithm for doing this efficiently, that doesn't run in O(N2) time, or worse? (Although even that would be ok; I'm not in a rush for results. Run time in even tens of seconds would be acceptable. Parsing the XML takes maybe 3–5 seconds; it's ~20 MB uncompressed. I mostly just want an algorithm that works. I thought I had something last night, but I got a recursion overflow when I ran it, and I'm supposed to be preparing for a job interview, not debugging a pointless game add-on.)

    This is complicated by the fact that there are many unnamed segments that also connect "Road" Nodes, and the named Seg elements by themselves may not form any complete paths. I'm assuming all of the unnamed segments must be considered as possibly having the same name as current named segment when looking for paths. However, even if they connect to the same node as the current named segment, they could belong to an intersecting road rather than the current one. So how to efficiently eliminate false connections is also a consideration in the algorithm.


  • Considered Harmful

    @HardwareGeek Your N here is going to devolve handily to n rather smaller M as you need only exhaust connections within a shared road name. You will need maps of collections for an initial collection under names.

    Resolving within a name won't fall down to box-based approaches since duplicated roads could run in diagonal parallel. You can, however, make the link-up more efficient by placing the ends in a quadtree or octtree.

    The case of a road that has a name at point A until B, another name from B to C, then resumes the original name, would be seen as a duplicate - if you hate that a lot, you will need to instead do linkup first, in which case you will need a quadtree.

    And, since my initial read ignored the presence of unnamed nodes, you will definitely need a spatial tree structure off the bat. You get N log N, (roughly)



  • @Gribnit said in Help Bites:

    our N here is going to devolve handily to n rather smaller M as you need only exhaust connections within a shared road name. You will need maps of collections for an initial collection under names.
    Resolving within a name won't fall down to box-based approaches since duplicated roads could run in diagonal parallel. You can, however, make the link-up more efficient by placing the ends in a quadtree or octtree.
    The case of a road that has a name at point A until B, another name from B to C, then resumes the original name, would be seen as a duplicate - if you hate that a lot, you will need to instead do linkup first, in which case you will need a quadtree.
    And, since my initial read ignored the presence of unnamed nodes, you will definitely need a spatial tree structure off the bat. You get N log N, (roughly)

    Yeah, this is an index problem for the discrete topology on a disconnected graph.


  • Discourse touched me in a no-no place

    @HardwareGeek My initial thought is that it sounds like a disjoint set problem where the condition for when to combine two segments is that they have a common name and share a node.


  • Considered Harmful

    @Captain said in Help Bites:

    @Gribnit said in Help Bites:

    our N here is going to devolve handily to n rather smaller M as you need only exhaust connections within a shared road name. You will need maps of collections for an initial collection under names.
    Resolving within a name won't fall down to box-based approaches since duplicated roads could run in diagonal parallel. You can, however, make the link-up more efficient by placing the ends in a quadtree or octtree.
    The case of a road that has a name at point A until B, another name from B to C, then resumes the original name, would be seen as a duplicate - if you hate that a lot, you will need to instead do linkup first, in which case you will need a quadtree.
    And, since my initial read ignored the presence of unnamed nodes, you will definitely need a spatial tree structure off the bat. You get N log N, (roughly)

    Yeah, this is an index problem for the discrete topology on a disconnected graph.

    My hope is that the compressed format has some help included, even a known order of appearance could help (if it's the link order it could help quite a bit).



  • @cvi said in Help Bites:

    Is there any way of testing stuff on MacOS without having to buy/borrow a Mac? I have to debug building and running some stuff (C/C++, so native code) on a Mac, because there are some people who are Apple-encumbered and don't have any great alternatives (and dealing with them individually is a pain).

    IIRC Microsoft provides pre-built Windows images for this kind of stuff, but as far as I can tell, Apple doesn't.

    I finally (many years ago now) just bought a lower-end machine. I'm now on my 3rd - a refurbed M1 Air.


  • Discourse touched me in a no-no place

    @cvi I assume you're asking for a work reason, and therefore the answer needs to be an official method?

    There are hosting providers that offer Mac Minis, but you're probably at the cost of just buying a low end Mac Mini within a year.



  • @dcon The idea has crossed my mind, and under normal circumstances, it'd be fairly reasonable. Unfortunately, it's for work, so buying a refurbished machine involves a bureaucratic battle that isn't worth it.

    @loopback0 said in Help Bites:

    There are hosting providers that offer Mac Minis, but you're probably at the cost of just buying a low end Mac Mini within a year.

    I saw a few such results while doing some initial searches. The initial hits gave a bit of a sketchy impression (and had generally shitty terms). If you know of a reputable service, I'd take a look.

    Ideally I need a few hours on a machine with dev tools - if this starts taking days, it's basically not worth it anyway.



  • @cvi said in Help Bites:

    it's for work

    Ideally I need a few hours on a machine with dev tools - if this starts taking days, it's basically not worth it anyway.

    I take it you can't convince your boss this is something that will actually be very useful to purchase? Seems the amount of time you'll spend finding and getting signoff on some online system would cost more than just getting a new system!



  • @dcon said in Help Bites:

    I take it you can't convince your boss this is something that will actually be very useful to purchase? Seems the amount of time you'll spend finding and getting signoff on some online system would cost more than just getting a new system!

    It's complicated(tm). My boss isn't the problem (and I don't even really have to ask). But purchases have to go through IT, so refurb is out of question, and a new machine would be IT-infected so a bureaucratic pain in the ass to get into a working state (e.g., install custom software) and it'd take months to get it.

    Cloud is probably easier (IT doesn't have a solution with MacOS there, so any bitching from their side can be averted -- I wouldn't even ask them in the first place).



  • @dkf said in Help Bites:

    For batch mode testing, you can use a macOS image in Github Actions;

    That seems to have worked. 👍



  • @cvi said in Help Bites:

    and it'd take months to get it

    That was the main thing I was worried about...

    IT-infected

    Well, after that.


  • 🚽 Regular

    @HardwareGeek Dump it all on SQLite and then you don't have to worry about algorithms, only SQL. :half-trolling:



  • This all seems like good info (even @Gribnit's 😲, which I have quoted below to keep it visible to me (although @Captain already quoted it, so I didn't really need to do that); the only reason I was able to see it at all is that it streamed in while I still had the window open to this thread), but it gets into data structures, like quadtrees, that I didn't learn about in school (30+ years ago, so even if I had learned about them, I'd have forgotten long ago) and other things, like graph theory, that I never learned about at all, so I'm still trying to figure out how to apply this info to my problem.

    In particular, most of the info I've found on quadtrees, disjoint-set data structures, and related topics talks about undirected, acyclic graphs. I'm not sure whether this graph is undirected, and if not, whether I care about the direction of edges (I think the game itself does; it is probably used to determine things like the orientation of one-way and other asymmetric roads, but I don't care about that for the purposes of this problem), but it is definitely not acyclic, even within a single named road. It may also be branching.

    Consider this roundabout and its connected roads. The roundabout itself is obviously a cycle. The entrance/exit roads at the bottom also form a cycle. The ones at the top are branches of the road at the top left, but aren't a cycle because the roundabout segment between them in the graph of the road named Cruise Boulevard because the roundabout segment isn't part of that graph. I'm fine with something like this being detected as duplicate road names; I can look at it and see that these are all supposed to be the same name. (I also consider it correct behavior to detect a road that is broken by a differently-named segment as duplicate names, because that is a situation I want flagged so that I can fix it.) I don't really care where/how the algorithm breaks the cycles; I just don't want the algorithm to get stuck in infinite looping/recursion trying to find the root of the cycles.

    Edit: I suppose it might help if I actually posted the screenshot:
    d9f364fd-c77e-470a-b82c-6ba278c432ad-image.png

    All this makes me wonder about the applicability of the suggestions, given this additional information.

    @Gribnit said in Help Bites:

    @HardwareGeek Your N here is going to devolve handily to n rather smaller M as you need only exhaust connections within a shared road name. You will need maps of collections for an initial collection under names.
    Resolving within a name won't fall down to box-based approaches since duplicated roads could run in diagonal parallel. You can, however, make the link-up more efficient by placing the ends in a quadtree or octtree.
    The case of a road that has a name at point A until B, another name from B to C, then resumes the original name, would be seen as a duplicate - if you hate that a lot, you will need to instead do linkup first, in which case you will need a quadtree.
    And, since my initial read ignored the presence of unnamed nodes, you will definitely need a spatial tree structure off the bat. You get N log N, (roughly)



  • @dkf said in Help Bites:

    @HardwareGeek My initial thought is that it sounds like a disjoint set problem where the condition for when to combine two segments is that they have a common name and share a node.

    Yes, with the caveat that an unnamed segment may take the place of one of the segments with a common name, and other unnamed segments may also share the same node but not be part of the set. I'm not sure how to include the correct unnamed segment (if any) and exclude the others; that is, how to identify the correct one.


  • Java Dev

    @HardwareGeek The problem may be simplified if you can limit yourself to a single unnamed segment, since then you could match named roads connected on either end simply by investigating the single unnamed segment. If there are multiple matches, I'd probably consider both connected.


  • Discourse touched me in a no-no place

    @HardwareGeek said in Help Bites:

    Yes, with the caveat that an unnamed segment may take the place of one of the segments with a common name, and other unnamed segments may also share the same node but not be part of the set. I'm not sure how to include the correct unnamed segment (if any) and exclude the others; that is, how to identify the correct one.

    That complicates things a lot, as there will be the cases where a unnamed segment connects two segments with different names.

    The disjoint-set stuff doesn't need a directed graph, just a way to avoid getting stuck in cycles. That's easy though: you just visit every segment once, in arbitrary order (such as the order you parse them in from the file). The algorithm stitches them together as it goes, and elegantly handles merging things. I first saw the algorithm presented for finding contiguous areas of an image with a consistent colour, which is an undirected problem and at much larger scale than yours; the guy who showed me said it was so fast he didn't bother optimising it further.


  • 🚽 Regular

    @Zecc said in Help Bites:

    @HardwareGeek Dump it all on SQLite and then you don't have to worry about algorithms, only SQL. :half-trolling:

    I'm not sure if it was clear I was only half-trolling.

    As I understand it, you could use Sqlite to implement a disjoint set.
    Have a table Roads of (RoadId, RoadName) and a table Segments of (SegmentId, StartNode, EndNode, RoadId).

    To add new segments, check if the current segment connects to an existing segment:

    roads =
        SELECT DISTINCT prev.roadId FROM Segments prev
          WHERE prev.RoadId = (SELECT roadId FROM Roads WHERE RoadName = @currRoadName) AND
          (prev.StartNode IN (@currentStartNode, @currentEndNode) OR prev.EndNode IN (@currentStartNode, @currentEndNode))
    

    Then depending on the numbers of results from the previous query:

    If len(roads) == 0, this segment does not connect anywhere else you've seen before, so create a new road even if it's going to be merged later.

    newRoadId = INSERT INTO Roads (RoadName) VALUES (@roadName)
    INSERT INTO Segments (StartNode, EndNode, RoadId) VALUES (@currStartNode, @currEndNode, @newRoadId)
    

    If len(roads) == 1, this segment connects to the one road you already know about, so add it to this road

    roadId = roads[0]
    INSERT INTO Segments (StartNode, EndNode, RoadId) VALUES (@currStartNode, @currEndNode, @roadId)
    

    If len(roads) == 2, then you've just found two roads which are now connected and should be merged, so merge them.

    road1Id, road2Id = (roads[0], roads[1])
    UPDATE Segments SET RoadId = @road1Id WHERE RoadId = @road2Id
    DELETE FROM Roads WHERE RoadId = @road2Id
    INSERT INTO Segments (StarNode, EndNode, RoadId) VALUES (@currStartNode, @currEndNode, @road1Id)
    

    If len(roads) > 2, you've failed to merge roads before, so that's a bug

    Once done, the tables should be an accurate representation, but do note this doesn't really deal with bifurcations. Shouldn't be too difficult to change the query to detect that though.


  • 🚽 Regular

    @dkf said in Help Bites:

    That complicates things a lot, as there will be the cases where a unnamed segment connects two segments with different names.

    Ouch. If there are unnamed segments, then there will be cases where it is ambiguous to which road a segment belongs.

    Which means not just this:

        Red Road                            Green Road
    ---------------o--------------------o---------------
    

    But also this:

        Red Road                            Green Road
    --------------\                      /--------------
                   o--------------------o
    --------------/                      \--------------
        Red Road                            Green Road
    

    And even this:

        Red Road                            Green Road
    --------------\                      /--------------
                   o--------------------o
    --------------/                      \--------------
       Green Road                            Red Road
    

    And good luck solving this riddle:

        Red Road                            Red Road
    --------------\                      /--------------
                   o--------------------o
    --------------/                      \--------------
       Green Road                            Red Road


  • @HardwareGeek said in Help Bites:

    on quadtrees

    Not sure what you'd do with a quadtree in this case. Your road structure is already connected by the node ids, so I don't think you need to rely on spatial data (and a quadtree is mainly a spatial data structure that allows you to locate things by a position).

    FWIW- my general approach to something like this is to process the data in steps, where the first few steps reduce the data. For example, I'm guessing that each Seg is a linear piece of road. That means that you likely have trivial 'roadlets' (i.e., no branches and same name, if any) made from multiple Segs . First goal would be to identify those, and reduce the graph structure to just represent the topology.

    For the data structure, I'd initially just try to get away with a few hash tables (there's probably at most a few M elements based on your file size estimates, so it's nothing too crazy).


  • Discourse touched me in a no-no place

    @Zecc said in Help Bites:

    But also this:

        Red Road                            Green Road
    --------------\                      /--------------
                   o--------------------o
    --------------/                      \--------------
        Red Road                            Green Road
    

    Simple minimization should handle that: the unnamed road is part of neither since the two ends of it don't connect to named roads with the same name.

    And even this:

        Red Road                            Green Road
    --------------\                      /--------------
                   o--------------------o
    --------------/                      \--------------
       Green Road                            Red Road
    

    That's a conflict, and is probably a case that should be highlighted. It certainly isn't safe for the computer to extend either name onto that segment.

    And good luck solving this riddle:

        Red Road                            Red Road
    --------------\                      /--------------
                   o--------------------o
    --------------/                      \--------------
       Green Road                            Red Road
    

    That's another easy one because the unnamed segments connects two (well, three) named segments with the same name and doesn't have any conflict from the other name.

    The problems will come from there being whole sequences of unnamed segments that could connect many possible named segments. Because of course that's going to happen. Again, you use the disjoint set stuff to group up connected unnamed segments so that you can try to see if you can pretend they're a single segment; I suspect that in many cases that will work, and in the rest it will reduce things to the point where it is possible to think about them as a human.


  • I survived the hour long Uno hand

    All y'all are overthinking this. The obvious answer is to write a script that periodically updates any new road names to Guid.NewGuid().ToString().


  • Java Dev

    @dkf said in Help Bites:

    @Zecc said in Help Bites:

    And even this:

        Red Road                            Green Road
    --------------\                      /--------------
                   o--------------------o
    --------------/                      \--------------
       Green Road                            Red Road
    

    That's a conflict, and is probably a case that should be highlighted. It certainly isn't safe for the computer to extend either name onto that segment.

    It's an interesting one because it does occur in reality. Particularly for road numbers, two differently numbered roads may join for a short distance then separate again. This happens with the A9 and A2 in this link, though openstreetmap tags the parallel road as A9, which is not quite correct.

    In this link, openstreetmaps correctly double-tags the N8 onto the N246 and N203, a situation which exists because the A8 was never extended to connect to the A9.


  • Banned

    @PleegWat AFAICT Google Maps handles it by marking the fragment with both road numbers. Which is the best solution I think.


  • Java Dev

    @Gustav I initially thought it didn't, which is why I linked openstreetmaps instead. It turns out it does show both, but you have to zoom in very far and then it shows one number in some placed and the other in others. Openstreetmaps actually shows both numbers in the same box, but you have to zoom in a bit further than my embed links do and I didn't verify the embed.


  • BINNED

    @HardwareGeek my rough idea would be:

    1. find all connected components, using union-find. (see @dkf's link above) The union-find part is as good as linear in the number of operations you do here, which itself should be O(E*d) where d is the maximum node degree (loop over all edges, compare to all edges sharing the same start or end node). Not much higher than linear in total.
    2. sort the CCs by name to find potential duplicates, or throw them in a hash-based lookup. (n log n vs. n, where n is the number of CCs, potentially n << E)
    3. for each pair of connected components with the same (non-empty) name, check if they have a shared connection to any of the empy-name components. If they do, union them together too. These should be quite small sets by now, so the quadratic part shouldn't matter.

    What remains should be connected components which are not adjacent to the same unnamed components, and should thus be considered duplicate if they have the same name.

    ETA: This treats @zecc's third puzzle as having both red and green connected by the unnamed segment, i.e. wildcard segments can play multiple roles at the same time.


  • Considered Harmful

    @cvi said in Help Bites:

    Not sure what you'd do with a quadtree in this case. Your road structure is already connected by the node ids, so I don't think you need to rely on spatial data (and a quadtree is mainly a spatial data structure that allows you to locate things by a position).

    It is? I had read this as the segs having their point data, vs their link data. The spatial structures were to accomplish the linkage. If the segs are already linked list nodes then you just use a map of non-unique linked lists - you can f memory for this, right? map key is each seg ID, lists are the actual roads, these can also be collected under their names. This would end up letting a road continue its name after a local change.


  • Java Dev

    @topspin said in Help Bites:

    What remains should be connected components which are not adjacent to the same unnamed components, and should thus be considered duplicate if they have the same name.

    This assumes unnamed clusters are generally small, which may or may not be a valid assumption.

    ETA: This treats @zecc's third puzzle as having both red and green connected by the unnamed segment, i.e. wildcard segments can play multiple roles at the same time.

    I'd tend towards this as well; others have been assuming he actually wants to assign names to the unnamed segments in which case this would be troublesome.

    An item I'd add to the algorithm is that you probably want to filter out non-road segments. Things like railways (which I don't think get named, but do link up to road nodes at level crossings) could mess up your algorithm.



  • @Gribnit said in Help Bites:

    It is? I had read this as the segs having their point data, vs their link data.

    That's how I read:

    which contain the id of the associated Nodes

    id != spatial location. Even if it's a spatial location, since you're only interested in equality (rather than more complex spatial queries), you can just discretize the coordinates (if they aren't already), and compute an unique id that way.

    (You can extend that further, for e.g. when you can't discretize the positions uniquely. Consider the hash table to be a cheapo sparse grid. Give it a large enough key -64 bits in 2D should be more than enough- and it'll even deal with teapots in stadiums...)



  • @PleegWat said in Help Bites:

    This assumes unnamed clusters are generally small, which may or may not be a valid assumption.

    It turns out it's not. In fact, it turns out this whole exercise has been pointless.

    I did some checking, and it turns out the map export utility simply doesn't export the names of a lot of streets. According to a discussion in the Steam workshop, it only exports names I've set myself, not the game's randomly assigned names, which completely defeats my purpose.

    Thanks for all your help, but it looks like unless I can reverse engineer the game's internal data format, I'm SOL. The game stores it's data in a general-purpose container, which can hold any number of data blocks of various types. The Colossal Order devs have a sense of humor; the format is called Colossal Raw Asset Package (CRAP). The container format is documented, including the type identifiers for the various contained blocks, but — apart from some well-known types like image textures (DDS) and meshes (FBX) — the data block contents are not, at least not that I have found.


  • Considered Harmful

    @cvi I never claimed to have read every sentence, or even most of them.



  • How would you go to have a C/C++ executable (or library) contain the last time/date it was linked (and not compiled)?

    __DATE__ and __TIME__ contain the date/time when the file that contains them was compiled. So if e.g. main() prints them and I modify another .cpp file, it still prints the time main() was compiled, not when that other file was recompiled.

    The creation (modification?) date of the library/executable file itself is a better indication though depending on how the file was manipulated after creation that might not be correct. Also if an application is linked with a library printing the time of the application itself won't reflect changes to the library (at least on Linux where the executable doesn't require re-linking, I think on Windows everything is re-linked as soon as one dependency changes?). Note that in that case the "link time" as mentioned in the first sentence of this post is also not what I'd want (I want to know the last time anything in the whole application + dependencies was changed).

    I don't think the standard build systems are smart enough to detect that a file must be recompiled because a macro value changed? I.e. if I pass -DCUR_DATE=... to the compiler, it won't recompile all files that use CUR_DATE automatically.

    At that point I'm thinking the best way is to put the code that uses __DATE__ in a separate file (to make it trivially fast to compile) and then find a way to tell the build system to always recompile this file whenever it scans the solution? (and call the code from that file wherever I need it) No idea how to do that (in CMake) though.

    Then I would get the last time the build system was run, which if nothing was changed since the previous run wouldn't be the most accurate thing, but probably close enough for what I want (which is to quickly find out from various test versions that are littered around my disk which one was built when i.e. which one contains which attempt at various hacks).


  • Discourse touched me in a no-no place

    @remi said in Help Bites:

    At that point I'm thinking the best way is to put the code that uses __DATE__ in a separate file (to make it trivially fast to compile) and then find a way to tell the build system to always recompile this file whenever it scans the solution? (and call the code from that file wherever I need it) No idea how to do that (in CMake) though.

    If that was Make, then you'd put the build of it in the rule that does the linking (trivial if your build uses, say, gcc to do the link step too; otherwise slightly longer to write out). You might be able to do tricks with symbol definitions and linker scripts to bind in a timestamp during the link, but that's far hackier IMO.

    For CMake, this appears to suggest some ideas. I don't use CMake and never have used CMake, so I can't evaluate how good any of the suggestions are. (The link on that page to the CMake issue tracker is a dead end; no action in many years except for moving it to a different tracker and losing lots of information along the way. ⛳ 👏 )



  • @dkf said in Help Bites:

    For CMake, this appears to suggest some ideas.

    Thanks. That do seem to be more or less what I want, now I just need to decide if it actually works and whether I'm ready to spend the time to do it properly or not...


  • BINNED

    @remi said in Help Bites:

    The creation (modification?) date of the library/executable file itself is a better indication though depending on how the file was manipulated after creation that might not be correct. Also if an application is linked with a library printing the time of the application itself won't reflect changes to the library (at least on Linux where the executable doesn't require re-linking, I think on Windows everything is re-linked as soon as one dependency changes?). Note that in that case the "link time" as mentioned in the first sentence of this post is also not what I'd want (I want to know the last time anything in the whole application + dependencies was changed).

    If your dependencies are DLLs/SOs, your build system probably won't notice when they are changed. But it sounds like that's more complicated than what you want, anyway.

    At that point I'm thinking the best way is to put the code that uses __DATE__ in a separate file (to make it trivially fast to compile) and then find a way to tell the build system to always recompile this file whenever it scans the solution? (and call the code from that file wherever I need it) No idea how to do that (in CMake) though.

    That's how I do it.
    I have a small code file that just contains a simple function returning the date (and git revision hash), which gets autogenerated by a script. The script is added as an extra target in the build system. Also no idea how to do that in cmake, but the SO answers @dkf linked to should help with that.

    One thing I want to add to those answers:
    My target is set up such that the script is always executed, but since it basically only contains the date but not the time, the autogenerated file doesn't actually change every build, only once per day (or commit). The script checks the contents of the file before it attempts to write it, so it doesn't overwrite it if the contents would be identical, preventing time stamp modifications the build system would pick up. Because linking is slow and doing it needlessly every time is annoying.



  • Thanks, that's good information.

    @topspin said in Help Bites:

    Because linking is slow and doing it needlessly every time is annoying.

    That is the nagging doubt that I have in the corner of my mind. If adding this (tiny) feature of being able to print the build date means I have to pay the (not-so-tiny) cost of a doing one or more additional links at each and every build... I will probably find the thing more annoying than useful!

    Still, that answers my question, so thanks again.


  • Discourse touched me in a no-no place

    @remi said in Help Bites:

    That is the nagging doubt that I have in the corner of my mind.

    Rewriting the executable post-link is one of the more exciting methods. The easiest way would be to store the build date as a fixed length string somewhere in close vicinity to some sort of marker that is otherwise not used but then you could locate the marker and directly edit the binary to update the build date. That would be pretty straight-forward. Doing the same with a variable-length encoding would potentially be a lot trickier.

    There's also the resource compiler on Windows. That might be easier... but I've done nothing with it for many years. The advantage here is that resources can also be read by system tools, and you could do a simple relink to embed it (no need for expensive LTO).

    And then re-sign the executable (if you're doing that sort of thing). If you make any change, you'll have to do that because digital signatures are meant to prevent altering things like the static string table.



  • @dkf said in Help Bites:

    Rewriting the executable post-link is one of the more exciting methods.

    Uh, yeah, I'd rather not start too many "exciting" things for what's just a tiny debug side effect...

    :homer_slowly_backing_into_hedge:

    There's also the resource compiler on Windows.

    Mmm, that's more interesting. Maybe I could extend that idea (I need something that works on Linux as well) by writing the date/time in a file that I just read at runtime. There's no relink needed, there's the cost of reading a file at runtime but honestly for what's basically a debug print, who cares? The drawback I can see is that I need to package that file with the application (or maybe sneak the string into a file that's already packaged), which makes the whole thing a bit visible ("hey, what's that file here?").

    And then re-sign the executable (if you're doing that sort of thing).

    Thankfully no. I don't want to have to deal with that, TYVM.


Log in to reply