Skip to content

Commit 67974a0

Browse files
committed
Add page about UUID references & breaking changes
1 parent 3969198 commit 67974a0

3 files changed

Lines changed: 271 additions & 0 deletions

File tree

74.8 KB
Loading

modules/user-manual/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
* xref:index.adoc[]
22
** xref:layers.adoc[]
33
** xref:licenses.adoc[]
4+
** xref:references.adoc[]
45
** Project Editor
56
*** xref:project-editor/assembly-data.adoc[]
67
*** xref:project-editor/output-jobs.adoc[]
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
= UUID References
2+
3+
[NOTE]
4+
====
5+
This is a somewhat advanced, technical section. It is intended to give power
6+
users more knowledge about the internal function of LibrePCB, as this knowledge
7+
can be useful to increase productivity and to reduce the likelihood of running
8+
into troubles caused by broken UUID references.
9+
10+
More technical details about references between library elements are available
11+
https://developers.librepcb.org/df/d4f/doc_library.html[here].
12+
====
13+
14+
== Purpose of References
15+
16+
In every EDA tool, libraries and projects are full of cross-references between
17+
different objects. For example, when attaching a wire to a pin in the schematic,
18+
the wire has to store a reference to that particular pin to successfully
19+
restore that connection when you open the schematic the next time.
20+
21+
Many EDA tools use the object's name as reference. For example when you connect
22+
a wire of the _GND_ net to the pin named _IN+_ of the component with the
23+
designator _U3_, the schematic editor stores a reference like `U3:IN+` for the
24+
attached wire in the schematic file. When opening the schematic the next time,
25+
the editor searches for a component with the designator _U3_ in the project
26+
library, and then for a pin named _IN+_ within this component to restore the
27+
wire connection.
28+
29+
This system works, but it comes with a big disadvantage. Whenever you rename
30+
any referenced object (e.g. renaming pin _IN+_ to _+_), all the references to
31+
this object will break, causing broken library elements or projects. So in fact
32+
it is not allowed to ever rename or move things, or you will run into troubles.
33+
A typical symptom is that the editor throws errors like "Component XYZ not
34+
found", for example after updating libraries and then opening an older project.
35+
36+
== References in LibrePCB
37+
38+
LibrePCB follows a different approach. Instead of referencing objects by
39+
their name, it assigns a random identifier to every newly created object, and
40+
uses this for all the references. In particular, it uses
41+
https://en.wikipedia.org/wiki/Universally_unique_identifier[universally unique identifiers (UUIDs)] which consist of 36 characters and look like
42+
_3da6ef2c-03ff-4ed1-a8b8-c8acf2ed0291_.
43+
44+
For example, when you add a pin to a symbol, the editor automatically generates
45+
and assigns a random UUID to the pin. You may give the pin a human-readable
46+
name like _IN+_, but the editor gives it a UUID like
47+
_cc3af4a4-cc26-4548-a026-468e1d689ab3_. This UUID is typically not user-facing,
48+
so usually you won't ever see it. But behind the scenes, LibrePCB uses this
49+
UUID for any references. So a wire in the schematic which is attached to
50+
a pin won't reference the pin like `U3:IN+` in other tools, but like
51+
`7b8fef14-64f9-4502-8094-7e2c1c0b6e9a:cc3af4a4-cc26-4548-a026-468e1d689ab3`
52+
where the first UUID refers to the component (_U3_) and the second UUID
53+
refers to a pin of it (_IN+_).
54+
55+
Now whenever you rename objects like a symbol pin, it will only affect the
56+
human-readable name, but not its UUID. The UUID of an existing object will
57+
never change, so all the references to it will stay intact.
58+
59+
== Drawbacks of UUIDs
60+
61+
This system comes with the advantage of keeping references intact even when
62+
renaming objects, thus avoiding broken library elements or projects after
63+
renaming or moving things. However, it also comes with some drawbacks you
64+
should be aware of.
65+
66+
=== Names Are Non-Functional
67+
68+
As LibrePCB itself only considers the UUIDs for making references, in fact
69+
it does not care about the name of objects. Names are only for _you_, not
70+
for LibrePCB.
71+
72+
Now when you make substantial renames to existing objects, like renaming pin
73+
_IN+_ to _IN-_ because you want to swap those two pins of an OpAmp, this will
74+
change the meaning of the symbol pins. The pin which was _IN+_ before is now
75+
_IN-_ and vice versa. However, since the underlying UUIDs were not changed,
76+
for LibrePCB the pin function has not changed either. So if a wire of the net
77+
_VBAT_ was attached to pin _IN+_ before the rename, that wire will remain
78+
attached to the same pin after the rename, even though it's now called _IN-_.
79+
80+
So, keep this in mind and be careful when changing the meaning of existing pins.
81+
In this particular example, it would be better to swap the positions of the
82+
two OpAmp pins instead of swapping their names, since swapping the positions
83+
will keep the relation between UUID and pin function.
84+
85+
=== Copy != Duplicate
86+
87+
The LibrePCB library editor allows you to copy existing library elements in
88+
two different ways, and it is crucial to know the difference of those
89+
operations to understand in which situation you need which of those.
90+
91+
Copy::
92+
The copy operation is provided in the library overview tab, called
93+
_Copy to Other Library_. This operation will **copy an existing library
94+
element 1:1 into another library, keeping all its UUIDs**. In fact, this
95+
operation just copies the files from one library into another. As the UUIDs
96+
are preserved in this operation, in fact **the copy still represents the same
97+
object** -- it is _not_ a new, independent symbol.
98+
+
99+
For example when you copy a symbol named _OpAmp_ into another library, and
100+
you rename the new copy to _Comparator_, in fact you won't have two symbols
101+
afterwards! Since both symbols still have the same UUID, LibrePCB will pick
102+
only one of them (the one with the higher version number) and considers the
103+
other as an (outdated) duplicate. That duplicate won't be listed anywhere,
104+
so it feels like it is lost.
105+
+
106+
The copy operation is only intended to **override** library elements from
107+
read-only remote libraries with your own modifications. If you're not happy
108+
with a library element from our official libraries, you can copy it into your
109+
local library, modify it, give it a higher version number and save it. LibrePCB
110+
will then use _your_ library element in place of the original library element.
111+
+
112+
[IMPORTANT]
113+
====
114+
**Except from this particular use-case, the copy operation is usually not the
115+
right operation.** If used wrongly, it can lead to surprising behavior.
116+
====
117+
118+
Save To::
119+
This operation is provided in the _Project Library Manager_ and is called
120+
_Copy elements to local library_. It is exactly the same as the _Copy_
121+
operation, just for copying library elements from a project into a library
122+
rather than between two libraries. It allows to add library elements from
123+
a project to your local library (keeping their UUIDs), so you can modify the
124+
elements or reuse them in other projects.
125+
126+
[#duplicate]
127+
Duplicate::
128+
This operation is provided in the library overview tab to duplicate a library
129+
element within the opened library. **In contrast to the _Copy_ operation, the
130+
_Duplicate_ operation generates new UUIDs for the duplicated library element
131+
and all its contained objects.** It is _not_ just a file copy operation.
132+
+
133+
This is the right operation to create a new library element which is similar
134+
to an existing element, so you don't have to start from scratch. For example
135+
when you want to create a symbol called _Comparator_, you can duplicate the
136+
existing _OpAmp_ symbol, rename it to _Comparator_, adjust its metadata,
137+
graphics and pins as desired, and save it. The result will be a new,
138+
independent _Comparator_ symbol which has no relation to _OpAmp_ anymore.
139+
All UUIDs are re-generated, so it is like a new symbol created manually
140+
from scratch.
141+
+
142+
[NOTE]
143+
====
144+
Usually, this is the operation you are looking for.
145+
====
146+
147+
[#breaking-changes]
148+
== Breaking Changes
149+
150+
As you may understand by now, the data structures of libraries and projects are
151+
full of references. A project consists of hundreds or thousands of wires,
152+
traces, nets, pins and pads which are all linked together by referencing
153+
each other. This is true for every EDA tool, no matter if references are
154+
made by names, UUIDs or anything else. References are everywhere.
155+
156+
Given this fact, it is also clear that there is always the risk of _broken_
157+
references. Imagine you add a symbol to a schematic and connect wires to
158+
its pins. Now you realize the symbol is not exactly correct as it has
159+
a pin which the real part doesn't have. So you open the symbol in the library
160+
editor, delete that pin, and save the symbol. Then you update the project's
161+
library (with the _Project Library Manager_ in LibrePCB) to update the symbol
162+
in your schematic with the new one. But you have already attached a wire to
163+
the pin which no longer exists. This means that the wire holds a reference
164+
to a pin that doesn't exist (anymore), a case which we call _broken reference_.
165+
166+
Some tools may silently ignore such broken references and try to revert to a
167+
valid state. In this particular case, they might silently disconnect the wire
168+
from the pin, leaving behind a "dead end" wire.
169+
170+
Other tools, like LibrePCB, are more strict about broken references. Instead
171+
of silently ignoring such (potentially unintended, dangerous) invalid
172+
situations, the tool throws an error to inform you about the problem. This
173+
may lead to a situation where you cannot open the project anymore until the
174+
problem is fixed (e.g. the deletion of the pin is reverted).
175+
176+
**To avoid headaches and wasted time, such situation should be avoided to
177+
happen at all.** In other words, it is highly recommended to never make
178+
so-called _breaking changes_ to existing library elements. If you have a
179+
situation like the described superfluous symbol pin, it is better to create
180+
a new library element (using the _Duplicate_ operation) and make the breaking
181+
changes there. Then just replace the wrong symbol in the schematics with the
182+
new one. Using this workflow, there will never be any broken references,
183+
causing no errors or other troubles.
184+
185+
== Making Breaking Changes
186+
187+
LibrePCB tries to prevent you from (accidentally) making breaking changes.
188+
Generally you don't need to worry about breaking changes in library elements
189+
-- whenever you made a breaking change to an existing library element, LibrePCB
190+
will warn you with this banner:
191+
192+
image::breaking-changes-banner.png[alt="Breaking changes banner"]
193+
194+
As soon as this red banner shows up, **the editor is put into read-only mode
195+
and saving is not possible anymore**. Now you have three options:
196+
197+
Undo::
198+
If the breaking change was not intended, you can just undo the change
199+
(kbd:[Ctrl+Z]) and the editor will leave the read-only mode automatically.
200+
201+
Duplicate::
202+
If you instead want to make the change in a new library element rather than
203+
breaking the opened element (as described/recommended in the
204+
<<duplicate,Duplicate>> section above), just click the menu:Duplicate[]
205+
button in the banner and make the changes in the newly opened tab. LibrePCB
206+
will then automatically undo the breaking changes in the existing library
207+
element to leave the read-only mode.
208+
209+
Unlock::
210+
The third option is the only dangerous one -- by pressing & holding the
211+
menu:Unlock[] button you can leave the read-only mode, so it will be possible
212+
to actually save the breaking changes to disk.
213+
+
214+
[IMPORTANT]
215+
====
216+
This operation is regularly the reason why inexperienced LibrePCB users end
217+
up in troubles and ask us for help, complain about errors, or even blaming us
218+
about bugs in the libraries or the tool -- bugs which don't exist!
219+
220+
So: **Only use the unlock feature if you have fully understood how our
221+
referencing system works, what breaking changes are, and what consequences
222+
they have.**
223+
224+
Simply put, there is only one case where it is safe to unlock and make
225+
breaking changes to an existing library element: **If that particular library
226+
element is not referenced yet from anywhere else.** For example a symbol is
227+
not referenced from anywhere else if it has never been loaded as a gate into
228+
a component. If you create a component using that particular symbol, the symbol
229+
is considered as referenced -- even though you never added it to a project.
230+
====
231+
+
232+
A typical case for using the unlock feature is to continue work on an
233+
unfinished library element. For example you started to create a new symbol
234+
today, but you have to shut down the computer before it is finished. Tomorrow
235+
you open the symbol again to continue working on it. In this case, LibrePCB
236+
will prevent you from making breaking changes, and you have to unlock it to
237+
continue work. It wouldn't be reasonable in this case to duplicate the
238+
unfinished library element -- just unlock it.
239+
+
240+
[TIP]
241+
====
242+
For unlocking, you need to press and hold the button for a moment. The required
243+
holding time depends on the age of the library element to unlock. For the
244+
typical use-case of continuing work on a library element you just created the
245+
day before, only a short hold time is needed. But to unlock a library
246+
element that has existed for a year, you need to hold the unlock button for
247+
several seconds because the older the library element is, the higher the
248+
probability that it has already been referenced from other objects, and
249+
therefore the higher the risk of troubles.
250+
251+
**So if a library element needs a long time to unlock, you should think twice
252+
about if you are really sure to make breaking changes to it.**
253+
====
254+
255+
== Recommendations
256+
257+
Here are some simple recommendations which help to avoid running into troubles
258+
due to broken references:
259+
260+
* **Never copy/move/modify files on the file system directly.** Always perform
261+
operations in LibrePCB, as LibrePCB will take care of UUID handling then.
262+
As soon as you edit files on the file system directly, there is no safety
263+
net anymore and you can run easily into a hell of a mess.
264+
* When creating new library elements by copying an existing library element,
265+
**use the _duplicate_ operation, not the _copy_ operation**. Generally,
266+
the _copy_ operation is almost never what you are looking for.
267+
* When the "breaking changes"-banner shows up in the library editor, **do not
268+
click on menu:Unlock[] unless you are 100% sure that the library element
269+
has not been used by another library element or a project yet.** If you
270+
are not 100% sure about this, use the _Duplicate_ operation.

0 commit comments

Comments
 (0)